forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			523 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			523 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// File: Source.cpp
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Desc: DirectShow  base classes - implements CSource, which is a Quartz
							 | 
						||
| 
								 | 
							
								//       source filter 'template.'
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Locking Strategy.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Hold the filter critical section (m_pFilter->pStateLock()) to serialise
							 | 
						||
| 
								 | 
							
								// access to functions. Note that, in general, this lock may be held
							 | 
						||
| 
								 | 
							
								// by a function when the worker thread may want to hold it. Therefore
							 | 
						||
| 
								 | 
							
								// if you wish to access shared state from the worker thread you will
							 | 
						||
| 
								 | 
							
								// need to add another critical section object. The execption is during
							 | 
						||
| 
								 | 
							
								// the threads processing loop, when it is safe to get the filter critical
							 | 
						||
| 
								 | 
							
								// section from within FillBuffer().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <streams.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// CSource::Constructor
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Initialise the pin count for the filter. The user will create the pins in
							 | 
						||
| 
								 | 
							
								// the derived class.
							 | 
						||
| 
								 | 
							
								CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid)
							 | 
						||
| 
								 | 
							
								    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
							 | 
						||
| 
								 | 
							
								      m_iPins(0),
							 | 
						||
| 
								 | 
							
								      m_paStreams(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr)
							 | 
						||
| 
								 | 
							
								    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
							 | 
						||
| 
								 | 
							
								      m_iPins(0),
							 | 
						||
| 
								 | 
							
								      m_paStreams(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(phr);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef UNICODE
							 | 
						||
| 
								 | 
							
								CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid)
							 | 
						||
| 
								 | 
							
								    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
							 | 
						||
| 
								 | 
							
								      m_iPins(0),
							 | 
						||
| 
								 | 
							
								      m_paStreams(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr)
							 | 
						||
| 
								 | 
							
								    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
							 | 
						||
| 
								 | 
							
								      m_iPins(0),
							 | 
						||
| 
								 | 
							
								      m_paStreams(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(phr);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// CSource::Destructor
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								CSource::~CSource()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /*  Free our pins and pin array */
							 | 
						||
| 
								 | 
							
								    while (m_iPins != 0) {
							 | 
						||
| 
								 | 
							
									// deleting the pins causes them to be removed from the array...
							 | 
						||
| 
								 | 
							
									delete m_paStreams[m_iPins - 1];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ASSERT(m_paStreams == NULL);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Add a new pin
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								HRESULT CSource::AddPin(__in CSourceStream *pStream)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(&m_cStateLock);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*  Allocate space for this pin and the old ones */
							 | 
						||
| 
								 | 
							
								    CSourceStream **paStreams = new CSourceStream *[m_iPins + 1];
							 | 
						||
| 
								 | 
							
								    if (paStreams == NULL) {
							 | 
						||
| 
								 | 
							
								        return E_OUTOFMEMORY;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (m_paStreams != NULL) {
							 | 
						||
| 
								 | 
							
								        CopyMemory((PVOID)paStreams, (PVOID)m_paStreams,
							 | 
						||
| 
								 | 
							
								                   m_iPins * sizeof(m_paStreams[0]));
							 | 
						||
| 
								 | 
							
								        paStreams[m_iPins] = pStream;
							 | 
						||
| 
								 | 
							
								        delete [] m_paStreams;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    m_paStreams = paStreams;
							 | 
						||
| 
								 | 
							
								    m_paStreams[m_iPins] = pStream;
							 | 
						||
| 
								 | 
							
								    m_iPins++;
							 | 
						||
| 
								 | 
							
								    return S_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Remove a pin - pStream is NOT deleted
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								HRESULT CSource::RemovePin(__in CSourceStream *pStream)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int i;
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < m_iPins; i++) {
							 | 
						||
| 
								 | 
							
								        if (m_paStreams[i] == pStream) {
							 | 
						||
| 
								 | 
							
								            if (m_iPins == 1) {
							 | 
						||
| 
								 | 
							
								                delete [] m_paStreams;
							 | 
						||
| 
								 | 
							
								                m_paStreams = NULL;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                /*  no need to reallocate */
							 | 
						||
| 
								 | 
							
										while (++i < m_iPins)
							 | 
						||
| 
								 | 
							
										    m_paStreams[i - 1] = m_paStreams[i];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            m_iPins--;
							 | 
						||
| 
								 | 
							
								            return S_OK;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return S_FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// FindPin
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Set *ppPin to the IPin* that has the id Id.
							 | 
						||
| 
								 | 
							
								// or to NULL if the Id cannot be matched.
							 | 
						||
| 
								 | 
							
								STDMETHODIMP CSource::FindPin(LPCWSTR Id, __deref_out IPin **ppPin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CheckPointer(ppPin,E_POINTER);
							 | 
						||
| 
								 | 
							
								    ValidateReadWritePtr(ppPin,sizeof(IPin *));
							 | 
						||
| 
								 | 
							
								    // The -1 undoes the +1 in QueryId and ensures that totally invalid
							 | 
						||
| 
								 | 
							
								    // strings (for which WstrToInt delivers 0) give a deliver a NULL pin.
							 | 
						||
| 
								 | 
							
								    int i = WstrToInt(Id) -1;
							 | 
						||
| 
								 | 
							
								    *ppPin = GetPin(i);
							 | 
						||
| 
								 | 
							
								    if (*ppPin!=NULL){
							 | 
						||
| 
								 | 
							
								        (*ppPin)->AddRef();
							 | 
						||
| 
								 | 
							
								        return NOERROR;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        return VFW_E_NOT_FOUND;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// FindPinNumber
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// return the number of the pin with this IPin* or -1 if none
							 | 
						||
| 
								 | 
							
								int CSource::FindPinNumber(__in IPin *iPin) {
							 | 
						||
| 
								 | 
							
								    int i;
							 | 
						||
| 
								 | 
							
								    for (i=0; i<m_iPins; ++i) {
							 | 
						||
| 
								 | 
							
								        if ((IPin *)(m_paStreams[i])==iPin) {
							 | 
						||
| 
								 | 
							
								            return i;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// GetPinCount
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Returns the number of pins this filter has
							 | 
						||
| 
								 | 
							
								int CSource::GetPinCount(void) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(&m_cStateLock);
							 | 
						||
| 
								 | 
							
								    return m_iPins;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// GetPin
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Return a non-addref'd pointer to pin n
							 | 
						||
| 
								 | 
							
								// needed by CBaseFilter
							 | 
						||
| 
								 | 
							
								CBasePin *CSource::GetPin(int n) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(&m_cStateLock);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // n must be in the range 0..m_iPins-1
							 | 
						||
| 
								 | 
							
								    // if m_iPins>n  && n>=0 it follows that m_iPins>0
							 | 
						||
| 
								 | 
							
								    // which is what used to be checked (i.e. checking that we have a pin)
							 | 
						||
| 
								 | 
							
								    if ((n >= 0) && (n < m_iPins)) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ASSERT(m_paStreams[n]);
							 | 
						||
| 
								 | 
							
									return m_paStreams[n];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// *
							 | 
						||
| 
								 | 
							
								// * --- CSourceStream ----
							 | 
						||
| 
								 | 
							
								// *
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Set Id to point to a CoTaskMemAlloc'd
							 | 
						||
| 
								 | 
							
								STDMETHODIMP CSourceStream::QueryId(__deref_out LPWSTR *Id) {
							 | 
						||
| 
								 | 
							
								    CheckPointer(Id,E_POINTER);
							 | 
						||
| 
								 | 
							
								    ValidateReadWritePtr(Id,sizeof(LPWSTR));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // We give the pins id's which are 1,2,...
							 | 
						||
| 
								 | 
							
								    // FindPinNumber returns -1 for an invalid pin
							 | 
						||
| 
								 | 
							
								    int i = 1+ m_pFilter->FindPinNumber(this);
							 | 
						||
| 
								 | 
							
								    if (i<1) return VFW_E_NOT_FOUND;
							 | 
						||
| 
								 | 
							
								    *Id = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * 12);
							 | 
						||
| 
								 | 
							
								    if (*Id==NULL) {
							 | 
						||
| 
								 | 
							
								       return E_OUTOFMEMORY;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    IntToWstr(i, *Id);
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// CSourceStream::Constructor
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// increments the number of pins present on the filter
							 | 
						||
| 
								 | 
							
								CSourceStream::CSourceStream(
							 | 
						||
| 
								 | 
							
								    __in_opt LPCTSTR pObjectName,
							 | 
						||
| 
								 | 
							
								    __inout HRESULT *phr,
							 | 
						||
| 
								 | 
							
								    __inout CSource *ps,
							 | 
						||
| 
								 | 
							
								    __in_opt LPCWSTR pPinName)
							 | 
						||
| 
								 | 
							
								    : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
							 | 
						||
| 
								 | 
							
								      m_pFilter(ps) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     *phr = m_pFilter->AddPin(this);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef UNICODE
							 | 
						||
| 
								 | 
							
								CSourceStream::CSourceStream(
							 | 
						||
| 
								 | 
							
								    __in_opt LPCSTR pObjectName,
							 | 
						||
| 
								 | 
							
								    __inout HRESULT *phr,
							 | 
						||
| 
								 | 
							
								    __inout CSource *ps,
							 | 
						||
| 
								 | 
							
								    __in_opt LPCWSTR pPinName)
							 | 
						||
| 
								 | 
							
								    : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
							 | 
						||
| 
								 | 
							
								      m_pFilter(ps) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     *phr = m_pFilter->AddPin(this);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// CSourceStream::Destructor
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Decrements the number of pins on this filter
							 | 
						||
| 
								 | 
							
								CSourceStream::~CSourceStream(void) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     m_pFilter->RemovePin(this);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// CheckMediaType
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Do we support this type? Provides the default support for 1 type.
							 | 
						||
| 
								 | 
							
								HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(m_pFilter->pStateLock());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CMediaType mt;
							 | 
						||
| 
								 | 
							
								    GetMediaType(&mt);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (mt == *pMediaType) {
							 | 
						||
| 
								 | 
							
								        return NOERROR;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return E_FAIL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// GetMediaType/3
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// By default we support only one type
							 | 
						||
| 
								 | 
							
								// iPosition indexes are 0-n
							 | 
						||
| 
								 | 
							
								HRESULT CSourceStream::GetMediaType(int iPosition, __inout CMediaType *pMediaType) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(m_pFilter->pStateLock());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (iPosition<0) {
							 | 
						||
| 
								 | 
							
								        return E_INVALIDARG;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (iPosition>0) {
							 | 
						||
| 
								 | 
							
								        return VFW_S_NO_MORE_ITEMS;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return GetMediaType(pMediaType);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Active
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The pin is active - start up the worker thread
							 | 
						||
| 
								 | 
							
								HRESULT CSourceStream::Active(void) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(m_pFilter->pStateLock());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    HRESULT hr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (m_pFilter->IsActive()) {
							 | 
						||
| 
								 | 
							
									return S_FALSE;	// succeeded, but did not allocate resources (they already exist...)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // do nothing if not connected - its ok not to connect to
							 | 
						||
| 
								 | 
							
								    // all pins of a source filter
							 | 
						||
| 
								 | 
							
								    if (!IsConnected()) {
							 | 
						||
| 
								 | 
							
								        return NOERROR;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hr = CBaseOutputPin::Active();
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ASSERT(!ThreadExists());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // start the thread
							 | 
						||
| 
								 | 
							
								    if (!Create()) {
							 | 
						||
| 
								 | 
							
								        return E_FAIL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Tell thread to initialize. If OnThreadCreate Fails, so does this.
							 | 
						||
| 
								 | 
							
								    hr = Init();
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr))
							 | 
						||
| 
								 | 
							
									return hr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return Pause();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Inactive
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Pin is inactive - shut down the worker thread
							 | 
						||
| 
								 | 
							
								// Waits for the worker to exit before returning.
							 | 
						||
| 
								 | 
							
								HRESULT CSourceStream::Inactive(void) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CAutoLock lock(m_pFilter->pStateLock());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    HRESULT hr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // do nothing if not connected - its ok not to connect to
							 | 
						||
| 
								 | 
							
								    // all pins of a source filter
							 | 
						||
| 
								 | 
							
								    if (!IsConnected()) {
							 | 
						||
| 
								 | 
							
								        return NOERROR;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // !!! need to do this before trying to stop the thread, because
							 | 
						||
| 
								 | 
							
								    // we may be stuck waiting for our own allocator!!!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hr = CBaseOutputPin::Inactive();  // call this first to Decommit the allocator
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
									return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (ThreadExists()) {
							 | 
						||
| 
								 | 
							
									hr = Stop();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
									    return hr;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									hr = Exit();
							 | 
						||
| 
								 | 
							
									if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
									    return hr;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Close();	// Wait for the thread to exit, then tidy up.
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // hr = CBaseOutputPin::Inactive();  // call this first to Decommit the allocator
							 | 
						||
| 
								 | 
							
								    //if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								    //	return hr;
							 | 
						||
| 
								 | 
							
								    //}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// ThreadProc
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// When this returns the thread exits
							 | 
						||
| 
								 | 
							
								// Return codes > 0 indicate an error occured
							 | 
						||
| 
								 | 
							
								DWORD CSourceStream::ThreadProc(void) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    HRESULT hr;  // the return code from calls
							 | 
						||
| 
								 | 
							
								    Command com;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    do {
							 | 
						||
| 
								 | 
							
									com = GetRequest();
							 | 
						||
| 
								 | 
							
									if (com != CMD_INIT) {
							 | 
						||
| 
								 | 
							
									    DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command")));
							 | 
						||
| 
								 | 
							
									    Reply((DWORD) E_UNEXPECTED);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								    } while (com != CMD_INIT);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing")));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hr = OnThreadCreate(); // perform set up tasks
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
							 | 
						||
| 
								 | 
							
								        OnThreadDestroy();
							 | 
						||
| 
								 | 
							
									Reply(hr);	// send failed return code from OnThreadCreate
							 | 
						||
| 
								 | 
							
								        return 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Initialisation suceeded
							 | 
						||
| 
								 | 
							
								    Reply(NOERROR);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Command cmd;
							 | 
						||
| 
								 | 
							
								    do {
							 | 
						||
| 
								 | 
							
									cmd = GetRequest();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch (cmd) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case CMD_EXIT:
							 | 
						||
| 
								 | 
							
									    Reply(NOERROR);
							 | 
						||
| 
								 | 
							
									    break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case CMD_RUN:
							 | 
						||
| 
								 | 
							
									    DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???")));
							 | 
						||
| 
								 | 
							
									    // !!! fall through???
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									case CMD_PAUSE:
							 | 
						||
| 
								 | 
							
									    Reply(NOERROR);
							 | 
						||
| 
								 | 
							
									    DoBufferProcessingLoop();
							 | 
						||
| 
								 | 
							
									    break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case CMD_STOP:
							 | 
						||
| 
								 | 
							
									    Reply(NOERROR);
							 | 
						||
| 
								 | 
							
									    break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
									    DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd));
							 | 
						||
| 
								 | 
							
									    Reply((DWORD) E_NOTIMPL);
							 | 
						||
| 
								 | 
							
									    break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								    } while (cmd != CMD_EXIT);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hr = OnThreadDestroy();	// tidy up.
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread.")));
							 | 
						||
| 
								 | 
							
								        return 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting")));
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// DoBufferProcessingLoop
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Grabs a buffer and calls the users processing function.
							 | 
						||
| 
								 | 
							
								// Overridable, so that different delivery styles can be catered for.
							 | 
						||
| 
								 | 
							
								HRESULT CSourceStream::DoBufferProcessingLoop(void) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Command com;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    OnThreadStartPlay();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    do {
							 | 
						||
| 
								 | 
							
									while (!CheckRequest(&com)) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    IMediaSample *pSample;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
							 | 
						||
| 
								 | 
							
									    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								                Sleep(1);
							 | 
						||
| 
								 | 
							
										continue;	// go round again. Perhaps the error will go away
							 | 
						||
| 
								 | 
							
											    // or the allocator is decommited & we will be asked to
							 | 
						||
| 
								 | 
							
											    // exit soon.
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    // Virtual function user will override.
							 | 
						||
| 
								 | 
							
									    hr = FillBuffer(pSample);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    if (hr == S_OK) {
							 | 
						||
| 
								 | 
							
										hr = Deliver(pSample);
							 | 
						||
| 
								 | 
							
								                pSample->Release();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // downstream filter returns S_FALSE if it wants us to
							 | 
						||
| 
								 | 
							
								                // stop or an error if it's reporting an error.
							 | 
						||
| 
								 | 
							
								                if(hr != S_OK)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr));
							 | 
						||
| 
								 | 
							
								                  return S_OK;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    } else if (hr == S_FALSE) {
							 | 
						||
| 
								 | 
							
								                // derived class wants us to stop pushing data
							 | 
						||
| 
								 | 
							
										pSample->Release();
							 | 
						||
| 
								 | 
							
										DeliverEndOfStream();
							 | 
						||
| 
								 | 
							
										return S_OK;
							 | 
						||
| 
								 | 
							
									    } else {
							 | 
						||
| 
								 | 
							
								                // derived class encountered an error
							 | 
						||
| 
								 | 
							
								                pSample->Release();
							 | 
						||
| 
								 | 
							
										DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));
							 | 
						||
| 
								 | 
							
								                DeliverEndOfStream();
							 | 
						||
| 
								 | 
							
								                m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
							 | 
						||
| 
								 | 
							
								                return hr;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // all paths release the sample
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // For all commands sent to us there must be a Reply call!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (com == CMD_RUN || com == CMD_PAUSE) {
							 | 
						||
| 
								 | 
							
									    Reply(NOERROR);
							 | 
						||
| 
								 | 
							
									} else if (com != CMD_STOP) {
							 | 
						||
| 
								 | 
							
									    Reply((DWORD) E_UNEXPECTED);
							 | 
						||
| 
								 | 
							
									    DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								    } while (com != CMD_STOP);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return S_FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |