1747 lines
39 KiB
C
1747 lines
39 KiB
C
/*
|
|
* Implements IBaseFilter for parsers. (internal)
|
|
*
|
|
* hidenori@a2.ctktv.ne.jp
|
|
*
|
|
* FIXME - handle errors/flushing correctly.
|
|
* FIXME - handle seeking.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
#include "mmsystem.h"
|
|
#include "winerror.h"
|
|
#include "strmif.h"
|
|
#include "control.h"
|
|
#include "vfwmsgs.h"
|
|
#include "evcode.h"
|
|
#include "uuids.h"
|
|
|
|
#include "debugtools.h"
|
|
DEFAULT_DEBUG_CHANNEL(quartz);
|
|
|
|
#include "quartz_private.h"
|
|
#include "parser.h"
|
|
#include "mtype.h"
|
|
#include "memalloc.h"
|
|
|
|
#define QUARTZ_MSG_EXITTHREAD (WM_APP+2)
|
|
#define QUARTZ_MSG_SEEK (WM_APP+3)
|
|
|
|
HRESULT CParserOutPinImpl_InitIMediaSeeking( CParserOutPinImpl* This );
|
|
void CParserOutPinImpl_UninitIMediaSeeking( CParserOutPinImpl* This );
|
|
HRESULT CParserOutPinImpl_InitIMediaPosition( CParserOutPinImpl* This );
|
|
void CParserOutPinImpl_UninitIMediaPosition( CParserOutPinImpl* This );
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CParserImpl internal thread
|
|
*
|
|
*/
|
|
|
|
static
|
|
void CParserImplThread_ClearAllRequests( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
This->m_ppOutPins[nIndex]->m_bReqUsed = FALSE;
|
|
This->m_ppOutPins[nIndex]->m_pReqSample = NULL;
|
|
}
|
|
}
|
|
|
|
static
|
|
void CParserImplThread_ReleaseAllRequests( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
if ( This->m_ppOutPins[nIndex]->m_bReqUsed )
|
|
{
|
|
if ( This->m_ppOutPins[nIndex]->m_pReqSample != NULL )
|
|
{
|
|
IMediaSample_Release(This->m_ppOutPins[nIndex]->m_pReqSample);
|
|
This->m_ppOutPins[nIndex]->m_pReqSample = NULL;
|
|
}
|
|
This->m_ppOutPins[nIndex]->m_bReqUsed = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
BOOL CParserImplThread_HasPendingSamples( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
if ( This->m_ppOutPins[nIndex]->m_bReqUsed &&
|
|
This->m_ppOutPins[nIndex]->m_pReqSample != NULL )
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
HRESULT CParserImplThread_FlushAllPendingSamples( CParserImpl* This )
|
|
{
|
|
HRESULT hr;
|
|
IMediaSample* pSample;
|
|
DWORD_PTR dwContext;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
/* remove all samples from queue. */
|
|
hr = IAsyncReader_BeginFlush(This->m_pReader);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
IAsyncReader_EndFlush(This->m_pReader);
|
|
|
|
/* remove all processed samples from queue. */
|
|
while ( 1 )
|
|
{
|
|
hr = IAsyncReader_WaitForNext(This->m_pReader,0,&pSample,&dwContext);
|
|
if ( hr != S_OK )
|
|
break;
|
|
}
|
|
|
|
CParserImplThread_ReleaseAllRequests(This);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserImplThread_SendEndOfStream( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
HRESULT hr;
|
|
HRESULT hrRet;
|
|
CParserOutPinImpl* pOutPin;
|
|
|
|
TRACE("(%p)\n",This);
|
|
if ( This->m_bSendEOS )
|
|
return NOERROR;
|
|
This->m_bSendEOS = TRUE;
|
|
|
|
hrRet = S_OK;
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
pOutPin = This->m_ppOutPins[nIndex];
|
|
hr = CPinBaseImpl_SendEndOfStream(&pOutPin->pin);
|
|
if ( FAILED(hr) )
|
|
{
|
|
if ( SUCCEEDED(hrRet) )
|
|
hrRet = hr;
|
|
}
|
|
else
|
|
{
|
|
if ( hr != S_OK && hrRet == S_OK )
|
|
hrRet = hr;
|
|
}
|
|
}
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
static HRESULT CParserImplThread_SendFlush( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
HRESULT hr;
|
|
HRESULT hrRet;
|
|
CParserOutPinImpl* pOutPin;
|
|
|
|
TRACE("(%p)\n",This);
|
|
hrRet = S_OK;
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
pOutPin = This->m_ppOutPins[nIndex];
|
|
hr = CPinBaseImpl_SendBeginFlush(&pOutPin->pin);
|
|
if ( FAILED(hr) )
|
|
{
|
|
if ( SUCCEEDED(hrRet) )
|
|
hrRet = hr;
|
|
}
|
|
else
|
|
{
|
|
if ( hr != S_OK && hrRet == S_OK )
|
|
hrRet = hr;
|
|
hr = CPinBaseImpl_SendEndFlush(&pOutPin->pin);
|
|
if ( FAILED(hr) )
|
|
hrRet = hr;
|
|
}
|
|
}
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
static void CParserImplThread_ErrorAbort( CParserImpl* This, HRESULT hr )
|
|
{
|
|
CBaseFilterImpl_MediaEventNotify(
|
|
&This->basefilter,EC_ERRORABORT,(LONG_PTR)hr,(LONG_PTR)0);
|
|
CParserImplThread_SendEndOfStream(This);
|
|
}
|
|
|
|
static
|
|
HRESULT CParserImplThread_ProcessNextSample( CParserImpl* This )
|
|
{
|
|
IMediaSample* pSample;
|
|
DWORD_PTR dwContext;
|
|
ULONG nIndex;
|
|
HRESULT hr;
|
|
CParserOutPinImpl* pOutPin;
|
|
MSG msg;
|
|
|
|
while ( 1 )
|
|
{
|
|
if ( PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) )
|
|
{
|
|
hr = NOERROR;
|
|
switch ( msg.message )
|
|
{
|
|
case QUARTZ_MSG_EXITTHREAD:
|
|
TRACE("(%p) EndThread\n",This);
|
|
CParserImplThread_FlushAllPendingSamples(This);
|
|
CParserImplThread_ClearAllRequests(This);
|
|
CParserImplThread_SendFlush(This);
|
|
CParserImplThread_SendEndOfStream(This);
|
|
TRACE("(%p) exit thread\n",This);
|
|
return S_FALSE;
|
|
case QUARTZ_MSG_SEEK:
|
|
FIXME("(%p) Seek\n",This);
|
|
CParserImplThread_FlushAllPendingSamples(This);
|
|
hr = CParserImplThread_SendFlush(This);
|
|
CParserImplThread_SendEndOfStream(This);
|
|
/* FIXME - process seeking. */
|
|
/* FIXME - Send NewSegment. */
|
|
break;
|
|
default:
|
|
FIXME( "invalid message %04u\n", (unsigned)msg.message );
|
|
hr = E_FAIL;
|
|
CParserImplThread_ErrorAbort(This,hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = IAsyncReader_WaitForNext(This->m_pReader,PARSER_POLL_INTERVAL,&pSample,&dwContext);
|
|
nIndex = (ULONG)dwContext;
|
|
if ( hr != VFW_E_TIMEOUT )
|
|
break;
|
|
}
|
|
if ( FAILED(hr) )
|
|
{
|
|
CParserImplThread_ErrorAbort(This,hr);
|
|
return hr;
|
|
}
|
|
|
|
pOutPin = This->m_ppOutPins[nIndex];
|
|
if ( pOutPin != NULL && pOutPin->m_bReqUsed )
|
|
{
|
|
if ( This->m_pHandler->pProcessSample != NULL )
|
|
hr = This->m_pHandler->pProcessSample(This,nIndex,pOutPin->m_llReqStart,pOutPin->m_lReqLength,pOutPin->m_pReqSample);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( pOutPin->m_pOutPinAllocator != NULL &&
|
|
pOutPin->m_pOutPinAllocator != This->m_pAllocator )
|
|
{
|
|
/* if pin has its own allocator, sample must be copied */
|
|
hr = IMemAllocator_GetBuffer( This->m_pAllocator, &pSample, NULL, NULL, 0 );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = QUARTZ_IMediaSample_Copy(
|
|
pSample, pOutPin->m_pReqSample, TRUE );
|
|
if ( SUCCEEDED(hr) )
|
|
hr = CPinBaseImpl_SendSample(&pOutPin->pin,pSample);
|
|
IMediaSample_Release(pSample);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = CPinBaseImpl_SendSample(&pOutPin->pin,pOutPin->m_pReqSample);
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
CParserImplThread_ErrorAbort(This,hr);
|
|
|
|
IMediaSample_Release(pOutPin->m_pReqSample);
|
|
pOutPin->m_pReqSample = NULL;
|
|
pOutPin->m_bReqUsed = FALSE;
|
|
}
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
hr = NOERROR;
|
|
|
|
TRACE("return %08lx\n",hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static
|
|
DWORD WINAPI CParserImplThread_Entry( LPVOID pv )
|
|
{
|
|
CParserImpl* This = (CParserImpl*)pv;
|
|
BOOL bReqNext;
|
|
ULONG nIndex = 0;
|
|
HRESULT hr;
|
|
REFERENCE_TIME rtSampleTimeStart, rtSampleTimeEnd;
|
|
LONGLONG llReqStart;
|
|
LONG lReqLength;
|
|
REFERENCE_TIME rtReqStart, rtReqStop;
|
|
IMediaSample* pSample;
|
|
MSG msg;
|
|
|
|
/* initialize the message queue. */
|
|
PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE );
|
|
|
|
CParserImplThread_ClearAllRequests(This);
|
|
|
|
/* resume the owner thread. */
|
|
SetEvent( This->m_hEventInit );
|
|
|
|
TRACE( "Enter message loop.\n" );
|
|
|
|
bReqNext = TRUE;
|
|
while ( 1 )
|
|
{
|
|
if ( bReqNext )
|
|
{
|
|
/* Get the next request. */
|
|
hr = This->m_pHandler->pGetNextRequest( This, &nIndex, &llReqStart, &lReqLength, &rtReqStart, &rtReqStop );
|
|
if ( FAILED(hr) )
|
|
{
|
|
CParserImplThread_ErrorAbort(This,hr);
|
|
break;
|
|
}
|
|
if ( hr != S_OK )
|
|
{
|
|
/* Flush pending samples. */
|
|
hr = S_OK;
|
|
while ( CParserImplThread_HasPendingSamples(This) )
|
|
{
|
|
hr = CParserImplThread_ProcessNextSample(This);
|
|
if ( hr != S_OK )
|
|
break;
|
|
}
|
|
if ( hr != S_OK )
|
|
{
|
|
/* notification is already sent */
|
|
break;
|
|
}
|
|
|
|
/* Send End Of Stream. */
|
|
hr = CParserImplThread_SendEndOfStream(This);
|
|
if ( hr != S_OK )
|
|
{
|
|
/* notification is already sent */
|
|
break;
|
|
}
|
|
|
|
/* Blocking... */
|
|
hr = CParserImplThread_ProcessNextSample(This);
|
|
if ( hr != S_OK )
|
|
{
|
|
/* notification is already sent */
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if ( This->m_ppOutPins[nIndex]->pin.pPinConnectedTo == NULL )
|
|
continue;
|
|
|
|
rtSampleTimeStart = This->basefilter.rtStart + llReqStart * QUARTZ_TIMEUNITS;
|
|
rtSampleTimeEnd = (llReqStart + lReqLength) * QUARTZ_TIMEUNITS;
|
|
bReqNext = FALSE;
|
|
}
|
|
|
|
if ( !This->m_ppOutPins[nIndex]->m_bReqUsed )
|
|
{
|
|
hr = IMemAllocator_GetBuffer( This->m_pAllocator, &pSample, NULL, NULL, 0 );
|
|
if ( FAILED(hr) )
|
|
{
|
|
CParserImplThread_ErrorAbort(This,hr);
|
|
break;
|
|
}
|
|
hr = IMediaSample_SetTime(pSample,&rtSampleTimeStart,&rtSampleTimeEnd);
|
|
if ( SUCCEEDED(hr) )
|
|
hr = IAsyncReader_Request(This->m_pReader,pSample,nIndex);
|
|
if ( FAILED(hr) )
|
|
{
|
|
CParserImplThread_ErrorAbort(This,hr);
|
|
break;
|
|
}
|
|
|
|
This->m_ppOutPins[nIndex]->m_bReqUsed = TRUE;
|
|
This->m_ppOutPins[nIndex]->m_pReqSample = pSample;
|
|
This->m_ppOutPins[nIndex]->m_llReqStart = llReqStart;
|
|
This->m_ppOutPins[nIndex]->m_lReqLength = lReqLength;
|
|
This->m_ppOutPins[nIndex]->m_rtReqStart = rtSampleTimeStart;
|
|
This->m_ppOutPins[nIndex]->m_rtReqStop = rtSampleTimeEnd;
|
|
bReqNext = TRUE;
|
|
continue;
|
|
}
|
|
|
|
hr = CParserImplThread_ProcessNextSample(This);
|
|
if ( hr != S_OK )
|
|
{
|
|
/* notification is already sent */
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CParserImpl internal methods
|
|
*
|
|
*/
|
|
|
|
static
|
|
void CParserImpl_SetAsyncReader( CParserImpl* This, IAsyncReader* pReader )
|
|
{
|
|
if ( This->m_pReader != NULL )
|
|
{
|
|
IAsyncReader_Release( This->m_pReader );
|
|
This->m_pReader = NULL;
|
|
}
|
|
if ( pReader != NULL )
|
|
{
|
|
This->m_pReader = pReader;
|
|
IAsyncReader_AddRef(This->m_pReader);
|
|
}
|
|
}
|
|
|
|
static
|
|
void CParserImpl_ReleaseOutPins( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
|
|
if ( This->m_ppOutPins != NULL )
|
|
{
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
if ( This->m_ppOutPins[nIndex] != NULL )
|
|
{
|
|
IUnknown_Release(This->m_ppOutPins[nIndex]->unk.punkControl);
|
|
This->m_ppOutPins[nIndex] = NULL;
|
|
}
|
|
}
|
|
QUARTZ_FreeMem(This->m_ppOutPins);
|
|
This->m_ppOutPins = NULL;
|
|
}
|
|
This->m_cOutStreams = 0;
|
|
}
|
|
|
|
static
|
|
BOOL CParserImpl_OutPinsAreConnected( CParserImpl* This )
|
|
{
|
|
QUARTZ_CompListItem* pItem;
|
|
IPin* pPin;
|
|
IPin* pPinPeer;
|
|
HRESULT hr;
|
|
|
|
QUARTZ_CompList_Lock( This->basefilter.pOutPins );
|
|
pItem = QUARTZ_CompList_GetFirst( This->basefilter.pOutPins );
|
|
while ( pItem != NULL )
|
|
{
|
|
if ( pItem == NULL )
|
|
break;
|
|
pPin = (IPin*)QUARTZ_CompList_GetItemPtr(pItem);
|
|
pPinPeer = NULL;
|
|
hr = IPin_ConnectedTo(pPin,&pPinPeer);
|
|
if ( hr == S_OK && pPinPeer != NULL )
|
|
{
|
|
IPin_Release(pPinPeer);
|
|
return TRUE;
|
|
}
|
|
pItem = QUARTZ_CompList_GetNext( This->basefilter.pOutPins, pItem );
|
|
}
|
|
QUARTZ_CompList_Unlock( This->basefilter.pOutPins );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
void CParserImpl_ReleaseListOfOutPins( CParserImpl* This )
|
|
{
|
|
QUARTZ_CompListItem* pItem;
|
|
|
|
QUARTZ_CompList_Lock( This->basefilter.pOutPins );
|
|
while ( 1 )
|
|
{
|
|
pItem = QUARTZ_CompList_GetFirst( This->basefilter.pOutPins );
|
|
if ( pItem == NULL )
|
|
break;
|
|
QUARTZ_CompList_RemoveComp(
|
|
This->basefilter.pOutPins,
|
|
QUARTZ_CompList_GetItemPtr(pItem) );
|
|
}
|
|
QUARTZ_CompList_Unlock( This->basefilter.pOutPins );
|
|
}
|
|
|
|
|
|
static
|
|
HRESULT CParserImpl_BeginThread( CParserImpl* This )
|
|
{
|
|
DWORD dwRes;
|
|
HANDLE hEvents[2];
|
|
|
|
if ( This->m_hEventInit != (HANDLE)NULL &&
|
|
This->m_hThread != (HANDLE)NULL )
|
|
return NOERROR;
|
|
|
|
This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
|
|
if ( This->m_hEventInit == (HANDLE)NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
/* create the processing thread. */
|
|
This->m_hThread = CreateThread(
|
|
NULL, 0,
|
|
CParserImplThread_Entry,
|
|
(LPVOID)This,
|
|
0, &This->m_dwThreadId );
|
|
if ( This->m_hThread == (HANDLE)NULL )
|
|
return E_FAIL;
|
|
|
|
hEvents[0] = This->m_hEventInit;
|
|
hEvents[1] = This->m_hThread;
|
|
|
|
dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
|
|
if ( dwRes != WAIT_OBJECT_0 )
|
|
return E_FAIL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static
|
|
void CParserImpl_EndThread( CParserImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
if ( This->m_hThread != (HANDLE)NULL )
|
|
{
|
|
if ( PostThreadMessageA(
|
|
This->m_dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 ) )
|
|
{
|
|
WaitForSingleObject( This->m_hThread, INFINITE );
|
|
}
|
|
CloseHandle( This->m_hThread );
|
|
This->m_hThread = (HANDLE)NULL;
|
|
This->m_dwThreadId = 0;
|
|
}
|
|
if ( This->m_hEventInit != (HANDLE)NULL )
|
|
{
|
|
CloseHandle( This->m_hEventInit );
|
|
This->m_hEventInit = (HANDLE)NULL;
|
|
}
|
|
}
|
|
|
|
static
|
|
HRESULT CParserImpl_MemCommit( CParserImpl* This )
|
|
{
|
|
HRESULT hr;
|
|
ULONG nIndex;
|
|
IMemAllocator* pAlloc;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
if ( This->m_pAllocator == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
hr = IMemAllocator_Commit( This->m_pAllocator );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
|
|
{
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
|
|
if ( pAlloc != NULL && pAlloc != This->m_pAllocator )
|
|
{
|
|
hr = IMemAllocator_Commit( pAlloc );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static
|
|
void CParserImpl_MemDecommit( CParserImpl* This )
|
|
{
|
|
ULONG nIndex;
|
|
IMemAllocator* pAlloc;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
if ( This->m_pAllocator != NULL )
|
|
IMemAllocator_Decommit( This->m_pAllocator );
|
|
|
|
if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
|
|
{
|
|
for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
|
|
{
|
|
pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
|
|
if ( pAlloc != NULL )
|
|
IMemAllocator_Decommit( pAlloc );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CParserImpl methods
|
|
*
|
|
*/
|
|
|
|
static HRESULT CParserImpl_OnActive( CBaseFilterImpl* pImpl )
|
|
{
|
|
CParserImpl_THIS(pImpl,basefilter);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
if ( !CParserImpl_OutPinsAreConnected(This) )
|
|
return NOERROR;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl )
|
|
{
|
|
CParserImpl_THIS(pImpl,basefilter);
|
|
HRESULT hr;
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
if ( !CParserImpl_OutPinsAreConnected(This) )
|
|
return NOERROR;
|
|
|
|
hr = CParserImpl_MemCommit(This);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
hr = CParserImpl_BeginThread(This);
|
|
if ( FAILED(hr) )
|
|
{
|
|
CParserImpl_EndThread(This);
|
|
return hr;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl )
|
|
{
|
|
CParserImpl_THIS(pImpl,basefilter);
|
|
|
|
FIXME( "(%p)\n", This );
|
|
|
|
CParserImpl_EndThread(This);
|
|
CParserImpl_MemDecommit(This);
|
|
This->m_bSendEOS = FALSE;
|
|
|
|
/* FIXME - reset streams. */
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
static const CBaseFilterHandlers filterhandlers =
|
|
{
|
|
CParserImpl_OnActive, /* pOnActive */
|
|
CParserImpl_OnInactive, /* pOnInactive */
|
|
CParserImpl_OnStop, /* pOnStop */
|
|
};
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CParserInPinImpl methods
|
|
*
|
|
*/
|
|
|
|
static HRESULT CParserInPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
|
|
{
|
|
CParserInPinImpl_THIS(pImpl,pin);
|
|
HRESULT hr;
|
|
ULONG nIndex;
|
|
IUnknown* punk;
|
|
IAsyncReader* pReader = NULL;
|
|
LPCWSTR pwszOutPinName;
|
|
IMemAllocator* pAllocActual;
|
|
AM_MEDIA_TYPE* pmt;
|
|
|
|
TRACE("(%p,%p)\n",This,pPin);
|
|
|
|
if ( This->pParser->m_pHandler->pInitParser == NULL ||
|
|
This->pParser->m_pHandler->pUninitParser == NULL ||
|
|
This->pParser->m_pHandler->pGetOutPinName == NULL ||
|
|
This->pParser->m_pHandler->pGetStreamType == NULL ||
|
|
This->pParser->m_pHandler->pCheckStreamType == NULL ||
|
|
This->pParser->m_pHandler->pGetAllocProp == NULL ||
|
|
This->pParser->m_pHandler->pGetNextRequest == NULL )
|
|
{
|
|
FIXME("this parser is not implemented.\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
/* at first, release all output pins. */
|
|
if ( CParserImpl_OutPinsAreConnected(This->pParser) )
|
|
return E_FAIL;
|
|
CParserImpl_ReleaseListOfOutPins(This->pParser);
|
|
CParserImpl_ReleaseOutPins(This->pParser);
|
|
|
|
CParserImpl_SetAsyncReader( This->pParser, NULL );
|
|
hr = IPin_QueryInterface( pPin, &IID_IAsyncReader, (void**)&pReader );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
CParserImpl_SetAsyncReader( This->pParser, pReader );
|
|
IAsyncReader_Release(pReader);
|
|
|
|
/* initialize parser. */
|
|
hr = This->pParser->m_pHandler->pInitParser(This->pParser,&This->pParser->m_cOutStreams);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
This->pParser->m_ppOutPins = (CParserOutPinImpl**)QUARTZ_AllocMem(
|
|
sizeof(CParserOutPinImpl*) * This->pParser->m_cOutStreams );
|
|
if ( This->pParser->m_ppOutPins == NULL )
|
|
return E_OUTOFMEMORY;
|
|
for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
|
|
This->pParser->m_ppOutPins[nIndex] = NULL;
|
|
|
|
/* create and initialize an allocator. */
|
|
hr = This->pParser->m_pHandler->pGetAllocProp(This->pParser,&This->pParser->m_propAlloc);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
if ( This->pParser->m_propAlloc.cbAlign == 0 )
|
|
This->pParser->m_propAlloc.cbAlign = 1;
|
|
|
|
if ( This->pParser->m_pAllocator == NULL )
|
|
{
|
|
hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&This->pParser->m_pAllocator );
|
|
IUnknown_Release(punk);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
}
|
|
pAllocActual = NULL;
|
|
hr = IAsyncReader_RequestAllocator(pReader,This->pParser->m_pAllocator,&This->pParser->m_propAlloc,&pAllocActual);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
IMemAllocator_Release(This->pParser->m_pAllocator);
|
|
This->pParser->m_pAllocator = pAllocActual;
|
|
|
|
/* create output pins. */
|
|
for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
|
|
{
|
|
pwszOutPinName = This->pParser->m_pHandler->pGetOutPinName(This->pParser,nIndex);
|
|
if ( pwszOutPinName == NULL )
|
|
return E_FAIL;
|
|
hr = QUARTZ_CreateParserOutPin(
|
|
This->pParser,
|
|
&This->pParser->m_csParser,
|
|
&This->pParser->m_ppOutPins[nIndex],
|
|
nIndex, pwszOutPinName );
|
|
if ( SUCCEEDED(hr) )
|
|
hr = QUARTZ_CompList_AddTailComp(
|
|
This->pParser->basefilter.pOutPins,
|
|
(IUnknown*)&(This->pParser->m_ppOutPins[nIndex]->pin),
|
|
NULL, 0 );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
pmt = &This->pParser->m_ppOutPins[nIndex]->m_mtOut;
|
|
QUARTZ_MediaType_Free( pmt );
|
|
ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
|
|
hr = This->pParser->m_pHandler->pGetStreamType(This->pParser,nIndex,pmt);
|
|
if ( FAILED(hr) )
|
|
{
|
|
ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
|
|
return hr;
|
|
}
|
|
This->pParser->m_ppOutPins[nIndex]->pin.cAcceptTypes = 1;
|
|
This->pParser->m_ppOutPins[nIndex]->pin.pmtAcceptTypes = pmt;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserInPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
|
|
{
|
|
CParserInPinImpl_THIS(pImpl,pin);
|
|
|
|
CParserImpl_OnInactive(&This->pParser->basefilter);
|
|
CParserImpl_OnStop(&This->pParser->basefilter);
|
|
if ( This->pParser->m_pHandler->pUninitParser != NULL )
|
|
This->pParser->m_pHandler->pUninitParser(This->pParser);
|
|
CParserImpl_SetAsyncReader( This->pParser, NULL );
|
|
if ( This->pParser->m_pAllocator != NULL )
|
|
{
|
|
IMemAllocator_Decommit(This->pParser->m_pAllocator);
|
|
IMemAllocator_Release(This->pParser->m_pAllocator);
|
|
This->pParser->m_pAllocator = NULL;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
|
|
{
|
|
CParserInPinImpl_THIS(pImpl,pin);
|
|
|
|
TRACE("(%p,%p)\n",This,pmt);
|
|
|
|
if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
|
|
return E_FAIL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static const CBasePinHandlers inputpinhandlers =
|
|
{
|
|
CParserInPinImpl_OnPreConnect, /* pOnPreConnect */
|
|
NULL, /* pOnPostConnect */
|
|
CParserInPinImpl_OnDisconnect, /* pOnDisconnect */
|
|
CParserInPinImpl_CheckMediaType, /* pCheckMediaType */
|
|
NULL, /* pQualityNotify */
|
|
NULL, /* pReceive */
|
|
NULL, /* pReceiveCanBlock */
|
|
NULL, /* pEndOfStream */
|
|
NULL, /* pBeginFlush */
|
|
NULL, /* pEndFlush */
|
|
NULL, /* pNewSegment */
|
|
};
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CParserOutPinImpl methods
|
|
*
|
|
*/
|
|
|
|
static HRESULT CParserOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
|
|
{
|
|
CParserOutPinImpl_THIS(pImpl,pin);
|
|
ALLOCATOR_PROPERTIES propReq;
|
|
ALLOCATOR_PROPERTIES propActual;
|
|
IMemAllocator* pAllocator;
|
|
HRESULT hr;
|
|
BOOL bNewAllocator = FALSE;
|
|
|
|
TRACE("(%p,%p)\n",This,pPin);
|
|
|
|
if ( This->pin.pMemInputPinConnectedTo == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
if ( This->m_pOutPinAllocator != NULL )
|
|
{
|
|
IMemAllocator_Release(This->m_pOutPinAllocator);
|
|
This->m_pOutPinAllocator = NULL;
|
|
}
|
|
|
|
/* try to use This->pParser->m_pAllocator. */
|
|
ZeroMemory( &propReq, sizeof(ALLOCATOR_PROPERTIES) );
|
|
hr = IMemInputPin_GetAllocatorRequirements(
|
|
This->pin.pMemInputPinConnectedTo, &propReq );
|
|
if ( propReq.cbAlign != 0 )
|
|
{
|
|
if ( This->pParser->m_propAlloc.cbAlign != ( This->pParser->m_propAlloc.cbAlign / propReq.cbAlign * propReq.cbAlign ) )
|
|
bNewAllocator = TRUE;
|
|
}
|
|
if ( propReq.cbPrefix != 0 )
|
|
bNewAllocator = TRUE;
|
|
if ( !bNewAllocator )
|
|
{
|
|
hr = IMemInputPin_NotifyAllocator(
|
|
This->pin.pMemInputPinConnectedTo,
|
|
This->pParser->m_pAllocator, FALSE );
|
|
if ( hr == NOERROR )
|
|
{
|
|
This->m_pOutPinAllocator = This->pParser->m_pAllocator;
|
|
IMemAllocator_AddRef(This->m_pOutPinAllocator);
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
hr = IMemInputPin_GetAllocator(
|
|
This->pin.pMemInputPinConnectedTo, &pAllocator );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
hr = IMemAllocator_SetProperties( pAllocator, &This->pParser->m_propAlloc, &propActual );
|
|
if ( SUCCEEDED(hr) )
|
|
hr = IMemInputPin_NotifyAllocator(
|
|
This->pin.pMemInputPinConnectedTo, pAllocator, FALSE );
|
|
if ( FAILED(hr) )
|
|
{
|
|
IMemAllocator_Release(pAllocator);
|
|
return hr;
|
|
}
|
|
|
|
This->m_pOutPinAllocator = pAllocator;
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
|
|
{
|
|
CParserOutPinImpl_THIS(pImpl,pin);
|
|
|
|
if ( This->m_pOutPinAllocator != NULL )
|
|
{
|
|
IMemAllocator_Release(This->m_pOutPinAllocator);
|
|
This->m_pOutPinAllocator = NULL;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CParserOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
|
|
{
|
|
CParserOutPinImpl_THIS(pImpl,pin);
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p,%p)\n",This,pmt);
|
|
if ( pmt == NULL )
|
|
return E_POINTER;
|
|
|
|
if ( This->pParser->m_pHandler->pCheckStreamType == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
hr = This->pParser->m_pHandler->pCheckStreamType( This->pParser, This->nStreamIndex, pmt );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
static const CBasePinHandlers outputpinhandlers =
|
|
{
|
|
NULL, /* pOnPreConnect */
|
|
CParserOutPinImpl_OnPostConnect, /* pOnPostConnect */
|
|
CParserOutPinImpl_OnDisconnect, /* pOnDisconnect */
|
|
CParserOutPinImpl_CheckMediaType, /* pCheckMediaType */
|
|
NULL, /* pQualityNotify */
|
|
OutputPinSync_Receive, /* pReceive */
|
|
OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */
|
|
OutputPinSync_EndOfStream, /* pEndOfStream */
|
|
OutputPinSync_BeginFlush, /* pBeginFlush */
|
|
OutputPinSync_EndFlush, /* pEndFlush */
|
|
OutputPinSync_NewSegment, /* pNewSegment */
|
|
};
|
|
|
|
/***************************************************************************
|
|
*
|
|
* new/delete CParserImpl
|
|
*
|
|
*/
|
|
|
|
/* can I use offsetof safely? - FIXME? */
|
|
static QUARTZ_IFEntry FilterIFEntries[] =
|
|
{
|
|
{ &IID_IPersist, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
|
|
{ &IID_IMediaFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
|
|
{ &IID_IBaseFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
|
|
};
|
|
|
|
static void QUARTZ_DestroyParser(IUnknown* punk)
|
|
{
|
|
CParserImpl_THIS(punk,unk);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
if ( This->m_pInPin != NULL )
|
|
CParserInPinImpl_OnDisconnect(&This->m_pInPin->pin);
|
|
|
|
CParserImpl_SetAsyncReader( This, NULL );
|
|
if ( This->m_pAllocator != NULL )
|
|
{
|
|
IMemAllocator_Release(This->m_pAllocator);
|
|
This->m_pAllocator = NULL;
|
|
}
|
|
if ( This->m_pInPin != NULL )
|
|
{
|
|
IUnknown_Release(This->m_pInPin->unk.punkControl);
|
|
This->m_pInPin = NULL;
|
|
}
|
|
CParserImpl_ReleaseOutPins( This );
|
|
|
|
DeleteCriticalSection( &This->m_csParser );
|
|
|
|
CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
|
|
}
|
|
|
|
HRESULT QUARTZ_CreateParser(
|
|
IUnknown* punkOuter,void** ppobj,
|
|
const CLSID* pclsidParser,
|
|
LPCWSTR pwszParserName,
|
|
LPCWSTR pwszInPinName,
|
|
const ParserHandlers* pHandler )
|
|
{
|
|
CParserImpl* This = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p,%p)\n",punkOuter,ppobj);
|
|
|
|
This = (CParserImpl*)
|
|
QUARTZ_AllocObj( sizeof(CParserImpl) );
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory( This, sizeof(CParserImpl) );
|
|
|
|
This->m_pInPin = NULL;
|
|
This->m_cOutStreams = 0;
|
|
This->m_ppOutPins = NULL;
|
|
This->m_pReader = NULL;
|
|
This->m_pAllocator = NULL;
|
|
ZeroMemory( &This->m_propAlloc, sizeof(ALLOCATOR_PROPERTIES) );
|
|
This->m_hEventInit = (HANDLE)NULL;
|
|
This->m_hThread = (HANDLE)NULL;
|
|
This->m_dwThreadId = 0;
|
|
This->m_bSendEOS = FALSE;
|
|
This->m_pHandler = pHandler;
|
|
This->m_pUserData = NULL;
|
|
|
|
QUARTZ_IUnkInit( &This->unk, punkOuter );
|
|
|
|
hr = CBaseFilterImpl_InitIBaseFilter(
|
|
&This->basefilter,
|
|
This->unk.punkControl,
|
|
pclsidParser,
|
|
pwszParserName,
|
|
&filterhandlers );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
/* construct this class. */
|
|
hr = S_OK;
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
QUARTZ_FreeObj(This);
|
|
return hr;
|
|
}
|
|
|
|
This->unk.pEntries = FilterIFEntries;
|
|
This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
|
|
This->unk.pOnFinalRelease = QUARTZ_DestroyParser;
|
|
InitializeCriticalSection( &This->m_csParser );
|
|
|
|
/* create the input pin. */
|
|
hr = QUARTZ_CreateParserInPin(
|
|
This,
|
|
&This->m_csParser,
|
|
&This->m_pInPin,
|
|
pwszInPinName );
|
|
if ( SUCCEEDED(hr) )
|
|
hr = QUARTZ_CompList_AddComp(
|
|
This->basefilter.pInPins,
|
|
(IUnknown*)&(This->m_pInPin->pin),
|
|
NULL, 0 );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
IUnknown_Release( This->unk.punkControl );
|
|
return hr;
|
|
}
|
|
|
|
*ppobj = (void*)&(This->unk);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* new/delete CParserInPinImpl
|
|
*
|
|
*/
|
|
|
|
/* can I use offsetof safely? - FIXME? */
|
|
static QUARTZ_IFEntry InPinIFEntries[] =
|
|
{
|
|
{ &IID_IPin, offsetof(CParserInPinImpl,pin)-offsetof(CParserInPinImpl,unk) },
|
|
{ &IID_IMemInputPin, offsetof(CParserInPinImpl,meminput)-offsetof(CParserInPinImpl,unk) },
|
|
};
|
|
|
|
static void QUARTZ_DestroyParserInPin(IUnknown* punk)
|
|
{
|
|
CParserInPinImpl_THIS(punk,unk);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
CPinBaseImpl_UninitIPin( &This->pin );
|
|
CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
|
|
}
|
|
|
|
HRESULT QUARTZ_CreateParserInPin(
|
|
CParserImpl* pFilter,
|
|
CRITICAL_SECTION* pcsPin,
|
|
CParserInPinImpl** ppPin,
|
|
LPCWSTR pwszPinName )
|
|
{
|
|
CParserInPinImpl* This = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
|
|
|
|
This = (CParserInPinImpl*)
|
|
QUARTZ_AllocObj( sizeof(CParserInPinImpl) );
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
QUARTZ_IUnkInit( &This->unk, NULL );
|
|
This->pParser = pFilter;
|
|
|
|
hr = CPinBaseImpl_InitIPin(
|
|
&This->pin,
|
|
This->unk.punkControl,
|
|
pcsPin,
|
|
&pFilter->basefilter,
|
|
pwszPinName,
|
|
FALSE,
|
|
&inputpinhandlers );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = CMemInputPinBaseImpl_InitIMemInputPin(
|
|
&This->meminput,
|
|
This->unk.punkControl,
|
|
&This->pin );
|
|
if ( FAILED(hr) )
|
|
{
|
|
CPinBaseImpl_UninitIPin( &This->pin );
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
QUARTZ_FreeObj(This);
|
|
return hr;
|
|
}
|
|
|
|
This->unk.pEntries = InPinIFEntries;
|
|
This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
|
|
This->unk.pOnFinalRelease = QUARTZ_DestroyParserInPin;
|
|
|
|
*ppPin = This;
|
|
|
|
TRACE("returned successfully.\n");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* new/delete CParserOutPinImpl
|
|
*
|
|
*/
|
|
|
|
/* can I use offsetof safely? - FIXME? */
|
|
static QUARTZ_IFEntry OutPinIFEntries[] =
|
|
{
|
|
{ &IID_IPin, offsetof(CParserOutPinImpl,pin)-offsetof(CParserOutPinImpl,unk) },
|
|
{ &IID_IQualityControl, offsetof(CParserOutPinImpl,qcontrol)-offsetof(CParserOutPinImpl,unk) },
|
|
{ &IID_IMediaSeeking, offsetof(CParserOutPinImpl,mediaseeking)-offsetof(CParserOutPinImpl,unk) },
|
|
{ &IID_IMediaPosition, offsetof(CParserOutPinImpl,mediaposition)-offsetof(CParserOutPinImpl,unk) },
|
|
};
|
|
|
|
static void QUARTZ_DestroyParserOutPin(IUnknown* punk)
|
|
{
|
|
CParserOutPinImpl_THIS(punk,unk);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
QUARTZ_MediaType_Free( &This->m_mtOut );
|
|
if ( This->m_pOutPinAllocator != NULL )
|
|
IMemAllocator_Release(This->m_pOutPinAllocator);
|
|
|
|
CParserOutPinImpl_UninitIMediaPosition(This);
|
|
CParserOutPinImpl_UninitIMediaSeeking(This);
|
|
CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
|
|
CPinBaseImpl_UninitIPin( &This->pin );
|
|
|
|
}
|
|
|
|
HRESULT QUARTZ_CreateParserOutPin(
|
|
CParserImpl* pFilter,
|
|
CRITICAL_SECTION* pcsPin,
|
|
CParserOutPinImpl** ppPin,
|
|
ULONG nStreamIndex,
|
|
LPCWSTR pwszPinName )
|
|
{
|
|
CParserOutPinImpl* This = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
|
|
|
|
This = (CParserOutPinImpl*)
|
|
QUARTZ_AllocObj( sizeof(CParserOutPinImpl) );
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
QUARTZ_IUnkInit( &This->unk, NULL );
|
|
This->pParser = pFilter;
|
|
This->nStreamIndex = nStreamIndex;
|
|
ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
|
|
This->m_pOutPinAllocator = NULL;
|
|
This->m_pUserData = NULL;
|
|
This->m_bReqUsed = FALSE;
|
|
This->m_pReqSample = NULL;
|
|
This->m_llReqStart = 0;
|
|
This->m_lReqLength = 0;
|
|
This->m_rtReqStart = 0;
|
|
This->m_rtReqStop = 0;
|
|
|
|
|
|
hr = CPinBaseImpl_InitIPin(
|
|
&This->pin,
|
|
This->unk.punkControl,
|
|
pcsPin,
|
|
&pFilter->basefilter,
|
|
pwszPinName,
|
|
TRUE,
|
|
&outputpinhandlers );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = CQualityControlPassThruImpl_InitIQualityControl(
|
|
&This->qcontrol,
|
|
This->unk.punkControl,
|
|
&This->pin );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = CParserOutPinImpl_InitIMediaSeeking(This);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = CParserOutPinImpl_InitIMediaPosition(This);
|
|
if ( FAILED(hr) )
|
|
{
|
|
CParserOutPinImpl_UninitIMediaSeeking(This);
|
|
}
|
|
}
|
|
if ( FAILED(hr) )
|
|
{
|
|
CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
|
|
}
|
|
}
|
|
if ( FAILED(hr) )
|
|
{
|
|
CPinBaseImpl_UninitIPin( &This->pin );
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
QUARTZ_FreeObj(This);
|
|
return hr;
|
|
}
|
|
|
|
This->unk.pEntries = OutPinIFEntries;
|
|
This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
|
|
This->unk.pOnFinalRelease = QUARTZ_DestroyParserOutPin;
|
|
|
|
*ppPin = This;
|
|
|
|
TRACE("returned successfully.\n");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* IMediaSeeking for CParserOutPinImpl
|
|
*
|
|
*/
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnQueryInterface(IMediaSeeking* iface,REFIID riid,void** ppobj)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
IMediaSeeking_fnAddRef(IMediaSeeking* iface)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->unk.punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
IMediaSeeking_fnRelease(IMediaSeeking* iface)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->unk.punkControl);
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetCapabilities(IMediaSeeking* iface,DWORD* pdwCaps)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnCheckCapabilities(IMediaSeeking* iface,DWORD* pdwCaps)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnIsFormatSupported(IMediaSeeking* iface,const GUID* pidFormat)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnQueryPreferredFormat(IMediaSeeking* iface,GUID* pidFormat)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetTimeFormat(IMediaSeeking* iface,GUID* pidFormat)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnIsUsingTimeFormat(IMediaSeeking* iface,const GUID* pidFormat)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnSetTimeFormat(IMediaSeeking* iface,const GUID* pidFormat)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetDuration(IMediaSeeking* iface,LONGLONG* pllDuration)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
/* the following line may produce too many FIXMEs... */
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetStopPosition(IMediaSeeking* iface,LONGLONG* pllPos)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetCurrentPosition(IMediaSeeking* iface,LONGLONG* pllPos)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnConvertTimeFormat(IMediaSeeking* iface,LONGLONG* pllOut,const GUID* pidFmtOut,LONGLONG llIn,const GUID* pidFmtIn)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnSetPositions(IMediaSeeking* iface,LONGLONG* pllCur,DWORD dwCurFlags,LONGLONG* pllStop,DWORD dwStopFlags)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetPositions(IMediaSeeking* iface,LONGLONG* pllCur,LONGLONG* pllStop)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetAvailable(IMediaSeeking* iface,LONGLONG* pllFirst,LONGLONG* pllLast)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnSetRate(IMediaSeeking* iface,double dblRate)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetRate(IMediaSeeking* iface,double* pdblRate)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaSeeking_fnGetPreroll(IMediaSeeking* iface,LONGLONG* pllPreroll)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaseeking);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
|
|
static ICOM_VTABLE(IMediaSeeking) imediaseeking =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
IMediaSeeking_fnQueryInterface,
|
|
IMediaSeeking_fnAddRef,
|
|
IMediaSeeking_fnRelease,
|
|
/* IMediaSeeking fields */
|
|
IMediaSeeking_fnGetCapabilities,
|
|
IMediaSeeking_fnCheckCapabilities,
|
|
IMediaSeeking_fnIsFormatSupported,
|
|
IMediaSeeking_fnQueryPreferredFormat,
|
|
IMediaSeeking_fnGetTimeFormat,
|
|
IMediaSeeking_fnIsUsingTimeFormat,
|
|
IMediaSeeking_fnSetTimeFormat,
|
|
IMediaSeeking_fnGetDuration,
|
|
IMediaSeeking_fnGetStopPosition,
|
|
IMediaSeeking_fnGetCurrentPosition,
|
|
IMediaSeeking_fnConvertTimeFormat,
|
|
IMediaSeeking_fnSetPositions,
|
|
IMediaSeeking_fnGetPositions,
|
|
IMediaSeeking_fnGetAvailable,
|
|
IMediaSeeking_fnSetRate,
|
|
IMediaSeeking_fnGetRate,
|
|
IMediaSeeking_fnGetPreroll,
|
|
};
|
|
|
|
HRESULT CParserOutPinImpl_InitIMediaSeeking( CParserOutPinImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
ICOM_VTBL(&This->mediaseeking) = &imediaseeking;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CParserOutPinImpl_UninitIMediaSeeking( CParserOutPinImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* IMediaPosition for CParserOutPinImpl
|
|
*
|
|
*/
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnQueryInterface(IMediaPosition* iface,REFIID riid,void** ppobj)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
IMediaPosition_fnAddRef(IMediaPosition* iface)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->unk.punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
IMediaPosition_fnRelease(IMediaPosition* iface)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->unk.punkControl);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnGetTypeInfoCount(IMediaPosition* iface,UINT* pcTypeInfo)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnGetTypeInfo(IMediaPosition* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnGetIDsOfNames(IMediaPosition* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnInvoke(IMediaPosition* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnget_Duration(IMediaPosition* iface,REFTIME* prefTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnput_CurrentPosition(IMediaPosition* iface,REFTIME refTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnget_CurrentPosition(IMediaPosition* iface,REFTIME* prefTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnget_StopTime(IMediaPosition* iface,REFTIME* prefTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnput_StopTime(IMediaPosition* iface,REFTIME refTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnget_PrerollTime(IMediaPosition* iface,REFTIME* prefTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnput_PrerollTime(IMediaPosition* iface,REFTIME refTime)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnput_Rate(IMediaPosition* iface,double dblRate)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
return IMediaSeeking_SetRate(CParserOutPinImpl_IMediaSeeking(This),dblRate);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnget_Rate(IMediaPosition* iface,double* pdblRate)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
return IMediaSeeking_GetRate(CParserOutPinImpl_IMediaSeeking(This),pdblRate);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnCanSeekForward(IMediaPosition* iface,LONG* pCanSeek)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
IMediaPosition_fnCanSeekBackward(IMediaPosition* iface,LONG* pCanSeek)
|
|
{
|
|
CParserOutPinImpl_THIS(iface,mediaposition);
|
|
|
|
FIXME("(%p)->() stub!\n",This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static ICOM_VTABLE(IMediaPosition) imediaposition =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
IMediaPosition_fnQueryInterface,
|
|
IMediaPosition_fnAddRef,
|
|
IMediaPosition_fnRelease,
|
|
/* IDispatch fields */
|
|
IMediaPosition_fnGetTypeInfoCount,
|
|
IMediaPosition_fnGetTypeInfo,
|
|
IMediaPosition_fnGetIDsOfNames,
|
|
IMediaPosition_fnInvoke,
|
|
/* IMediaPosition fields */
|
|
IMediaPosition_fnget_Duration,
|
|
IMediaPosition_fnput_CurrentPosition,
|
|
IMediaPosition_fnget_CurrentPosition,
|
|
IMediaPosition_fnget_StopTime,
|
|
IMediaPosition_fnput_StopTime,
|
|
IMediaPosition_fnget_PrerollTime,
|
|
IMediaPosition_fnput_PrerollTime,
|
|
IMediaPosition_fnput_Rate,
|
|
IMediaPosition_fnget_Rate,
|
|
IMediaPosition_fnCanSeekForward,
|
|
IMediaPosition_fnCanSeekBackward,
|
|
};
|
|
|
|
|
|
HRESULT CParserOutPinImpl_InitIMediaPosition( CParserOutPinImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
ICOM_VTBL(&This->mediaposition) = &imediaposition;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CParserOutPinImpl_UninitIMediaPosition( CParserOutPinImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
}
|
|
|