Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
522
Src/Plugins/Input/in_dshow/base/source.cpp
Normal file
522
Src/Plugins/Input/in_dshow/base/source.cpp
Normal file
|
@ -0,0 +1,522 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue