包裝ffmpeg中的codecs成為DirectShow中的transform filter

源代码在线查看: source.cpp

软件大小: 5289 K
上传用户: chmqn
关键词: DirectShow transform ffmpeg codecs
下载地址: 免注册下载 普通下载 VIP

相关代码

				//------------------------------------------------------------------------------
				// File: Source.cpp
				//
				// Desc: DirectShow  base classes - implements CSource, which is a Quartz
				//       source filter 'template.'
				//
				// Copyright (c) 1992-2002 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 
				
				
				//
				// CSource::Constructor
				//
				// Initialise the pin count for the filter. The user will create the pins in
				// the derived class.
				CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid)
				    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
				      m_iPins(0),
				      m_paStreams(NULL)
				{
				}
				
				CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr)
				    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
				      m_iPins(0),
				      m_paStreams(NULL)
				{
				    UNREFERENCED_PARAMETER(phr);
				}
				
				#ifdef UNICODE
				CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid)
				    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
				      m_iPins(0),
				      m_paStreams(NULL)
				{
				}
				
				CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, 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(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(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, 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(IPin *iPin) {
				    int i;
				    for (i=0; 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(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				    *Id = (LPWSTR)CoTaskMemAlloc(8);
				    if (*Id==NULL) {
				       return E_OUTOFMEMORY;
				    }
				    IntToWstr(i, *Id);
				    return NOERROR;
				}
				
				
				
				//
				// CSourceStream::Constructor
				//
				// increments the number of pins present on the filter
				CSourceStream::CSourceStream(
				    TCHAR *pObjectName,
				    HRESULT *phr,
				    CSource *ps,
				    LPCWSTR pPinName)
				    : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
				      m_pFilter(ps) {
				
				     *phr = m_pFilter->AddPin(this);
				}
				
				#ifdef UNICODE
				CSourceStream::CSourceStream(
				    char *pObjectName,
				    HRESULT *phr,
				    CSource *ps,
				    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, CMediaType *pMediaType) {
				
				    CAutoLock lock(m_pFilter->pStateLock());
				
				    if (iPosition				        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;
				}
				
							

相关资源