transfrm.cpp.svn-base
来自「ffshow源码」· SVN-BASE 代码 · 共 1,027 行 · 第 1/2 页
SVN-BASE
1,027 行
//------------------------------------------------------------------------------// File: Transfrm.cpp//// Desc: DirectShow base classes - implements class for simple transform// filters such as video decompressors.//// Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.//------------------------------------------------------------------------------#include "stdafx.h"//#include <measure.h>// =================================================================// Implements the CTransformFilter class// =================================================================CTransformFilter::CTransformFilter(const TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid) : CBaseFilter(pName,pUnk,&m_csFilter, clsid), m_pInput(NULL), m_pOutput(NULL), m_bEOSDelivered(FALSE), m_bQualityChanged(FALSE), m_bSampleSkipped(FALSE){#ifdef PERF RegisterPerfId();#endif // PERF}// destructorCTransformFilter::~CTransformFilter(){ // Delete the pins delete m_pInput; delete m_pOutput;}// Transform place holder - should never be calledHRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut){ UNREFERENCED_PARAMETER(pIn); UNREFERENCED_PARAMETER(pOut); DbgBreak("CTransformFilter::Transform() should never be called"); return E_UNEXPECTED;}// return the number of pins we provideint CTransformFilter::GetPinCount(){ return 2;}// return a non-addrefed CBasePin * for the user to addref if he holds onto it// for longer than his pointer to us. We create the pins dynamically when they// are asked for rather than in the constructor. This is because we want to// give the derived class an oppportunity to return different pin objects// We return the objects as and when they are needed. If either of these fails// then we return NULL, the assumption being that the caller will realise the// whole deal is off and destroy us - which in turn will delete everything.CBasePin *CTransformFilter::GetPin(int n){ HRESULT hr = S_OK; // Create an input pin if necessary if (m_pInput == NULL) { m_pInput = new CTransformInputPin(NAME("Transform input pin"), this, // Owner filter &hr, // Result code L"XForm In"); // Pin name // Can't fail ASSERT(SUCCEEDED(hr)); if (m_pInput == NULL) { return NULL; } m_pOutput = (CTransformOutputPin *) new CTransformOutputPin(NAME("Transform output pin"), this, // Owner filter &hr, // Result code L"XForm Out"); // Pin name // Can't fail ASSERT(SUCCEEDED(hr)); if (m_pOutput == NULL) { delete m_pInput; m_pInput = NULL; } } // Return the appropriate pin if (n == 0) { return m_pInput; } else if (n == 1) { return m_pOutput; } else { return NULL; }}//// FindPin//// If Id is In or Out then return the IPin* for that pin// creating the pin if need be. Otherwise return NULL with an error.STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin){ CheckPointer(ppPin,E_POINTER); ValidateReadWritePtr(ppPin,sizeof(IPin *)); if (0==lstrcmpW(Id,L"In")) { *ppPin = GetPin(0); } else if (0==lstrcmpW(Id,L"Out")) { *ppPin = GetPin(1); } else { *ppPin = NULL; return VFW_E_NOT_FOUND; } HRESULT hr = NOERROR; // AddRef() returned pointer - but GetPin could fail if memory is low. if (*ppPin) { (*ppPin)->AddRef(); } else { hr = E_OUTOFMEMORY; // probably. There's no pin anyway. } return hr;}// override these two functions if you want to inform something// about entry to or exit from streaming state.HRESULTCTransformFilter::StartStreaming(){ return NOERROR;}HRESULTCTransformFilter::StopStreaming(){ return NOERROR;}// override this to grab extra interfaces on connectionHRESULTCTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin){ UNREFERENCED_PARAMETER(dir); UNREFERENCED_PARAMETER(pPin); return NOERROR;}// place holder to allow derived classes to release any extra interfacesHRESULTCTransformFilter::BreakConnect(PIN_DIRECTION dir){ UNREFERENCED_PARAMETER(dir); return NOERROR;}// Let derived classes know about connection completionHRESULTCTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin){ UNREFERENCED_PARAMETER(direction); UNREFERENCED_PARAMETER(pReceivePin); return NOERROR;}// override this to know when the media type is really setHRESULTCTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt){ UNREFERENCED_PARAMETER(direction); UNREFERENCED_PARAMETER(pmt); return NOERROR;}// Set up our output sampleHRESULTCTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample){ IMediaSample *pOutSample; // default - times are the same AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; // This will prevent the image renderer from switching us to DirectDraw // when we can't do it without skipping frames because we're not on a // keyframe. If it really has to switch us, it still will, but then we // will have to wait for the next keyframe if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { dwFlags |= AM_GBF_NOTASYNCPOINT; } ASSERT(m_pOutput->m_pAllocator != NULL); HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( &pOutSample , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? &pProps->tStart : NULL , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? &pProps->tStop : NULL , dwFlags ); *ppOutSample = pOutSample; if (FAILED(hr)) { return hr; } ASSERT(pOutSample); IMediaSample2 *pOutSample2; if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, (void **)&pOutSample2))) { /* Modify it */ AM_SAMPLE2_PROPERTIES OutProps; EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) )); OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; OutProps.dwSampleFlags = (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); OutProps.tStart = pProps->tStart; OutProps.tStop = pProps->tStop; OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); hr = pOutSample2->SetProperties( FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps ); if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { m_bSampleSkipped = FALSE; } pOutSample2->Release(); } else { if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { pOutSample->SetTime(&pProps->tStart, &pProps->tStop); } if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { pOutSample->SetSyncPoint(TRUE); } if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { pOutSample->SetDiscontinuity(TRUE); m_bSampleSkipped = FALSE; } // Copy the media times LONGLONG MediaStart, MediaEnd; if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { pOutSample->SetMediaTime(&MediaStart,&MediaEnd); } } return S_OK;}// override this to customize the transform processHRESULTCTransformFilter::Receive(IMediaSample *pSample){ /* Check for other streams and pass them on */ AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); if (pProps->dwStreamId != AM_STREAM_MEDIA) { return m_pOutput->m_pInputPin->Receive(pSample); } HRESULT hr; ASSERT(pSample); IMediaSample * pOutSample; // If no output to deliver to then no point sending us data ASSERT (m_pOutput != NULL) ; // Set up the output sample hr = InitializeOutputSample(pSample, &pOutSample); if (FAILED(hr)) { return hr; } // Start timing the transform (if PERF is defined) //MSR_START(m_idTransform); // have the derived class transform the data hr = Transform(pSample, pOutSample); // Stop the clock and log it (if PERF is defined) //MSR_STOP(m_idTransform); if (FAILED(hr)) { DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); } else { // the Transform() function can return S_FALSE to indicate that the // sample should not be delivered; we only deliver the sample if it's // really S_OK (same as NOERROR, of course.) if (hr == NOERROR) { hr = m_pOutput->m_pInputPin->Receive(pOutSample); m_bSampleSkipped = FALSE; // last thing no longer dropped } else { // S_FALSE returned from Transform is a PRIVATE agreement // We should return NOERROR from Receive() in this cause because returning S_FALSE // from Receive() means that this is the end of the stream and no more data should // be sent. if (S_FALSE == hr) { // Release the sample before calling notify to avoid // deadlocks if the sample holds a lock on the system // such as DirectDraw buffers do pOutSample->Release(); m_bSampleSkipped = TRUE; if (!m_bQualityChanged) { NotifyEvent(EC_QUALITY_CHANGE,0,0); m_bQualityChanged = TRUE; } return NOERROR; } } } // release the output buffer. If the connected pin still needs it, // it will have addrefed it itself. pOutSample->Release(); return hr;}// Return S_FALSE to mean "pass the note on upstream"// Return NOERROR (Same as S_OK)// to mean "I've done something about it, don't pass it on"HRESULT CTransformFilter::AlterQuality(Quality q){ UNREFERENCED_PARAMETER(q); return S_FALSE;}// EndOfStream received. Default behaviour is to deliver straight// downstream, since we have no queued data. If you overrode Receive// and have queue data, then you need to handle this and deliver EOS after// all queued data is sentHRESULTCTransformFilter::EndOfStream(void){ HRESULT hr = NOERROR; if (m_pOutput != NULL) { hr = m_pOutput->DeliverEndOfStream(); } return hr;}// enter flush state. Receives already blocked// must override this if you have queued data or a worker threadHRESULTCTransformFilter::BeginFlush(void){ HRESULT hr = NOERROR; if (m_pOutput != NULL) { // block receives -- done by caller (CBaseInputPin::BeginFlush) // discard queued data -- we have no queued data // free anyone blocked on receive - not possible in this filter // call downstream hr = m_pOutput->DeliverBeginFlush(); } return hr;}// leave flush state. must override this if you have queued data// or a worker threadHRESULTCTransformFilter::EndFlush(void){ // sync with pushing thread -- we have no worker thread // ensure no more data to go downstream -- we have no queued data // call EndFlush on downstream pins ASSERT (m_pOutput != NULL); return m_pOutput->DeliverEndFlush(); // caller (the input pin's method) will unblock Receives}// override these so that the derived filter can catch themSTDMETHODIMPCTransformFilter::Stop(){ CAutoLock lck1(&m_csFilter); if (m_State == State_Stopped) { return NOERROR; } // Succeed the Stop if we are not completely connected ASSERT(m_pInput == NULL || m_pOutput != NULL); if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || m_pOutput->IsConnected() == FALSE) { m_State = State_Stopped; m_bEOSDelivered = FALSE; return NOERROR; } ASSERT(m_pInput); ASSERT(m_pOutput); // decommit the input pin before locking or we can deadlock m_pInput->Inactive(); // synchronize with Receive calls CAutoLock lck2(&m_csReceiveProtector); CAutoLock lck3(&m_csReceive); m_pOutput->Inactive(); // allow a class derived from CTransformFilter // to know about starting and stopping streaming HRESULT hr = StopStreaming(); if (SUCCEEDED(hr)) { // complete the state transition m_State = State_Stopped; m_bEOSDelivered = FALSE; } return hr;}STDMETHODIMPCTransformFilter::Pause(){ CAutoLock lck(&m_csFilter); HRESULT hr = NOERROR; if (m_State == State_Paused) { // (This space left deliberately blank) } // If we have no input pin or it isn't yet connected then when we are // asked to pause we deliver an end of stream to the downstream filter. // This makes sure that it doesn't sit there forever waiting for // samples which we cannot ever deliver without an input connection. else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { if (m_pOutput && m_bEOSDelivered == FALSE) { m_pOutput->DeliverEndOfStream(); m_bEOSDelivered = TRUE; } m_State = State_Paused; } // We may have an input connection but no output connection // However, if we have an input pin we do have an output pin else if (m_pOutput->IsConnected() == FALSE) { m_State = State_Paused; } else { if (m_State == State_Stopped) { // allow a class derived from CTransformFilter // to know about starting and stopping streaming CAutoLock lck2(&m_csReceiveProtector); CAutoLock lck3(&m_csReceive); hr = StartStreaming(); } if (SUCCEEDED(hr)) { hr = CBaseFilter::Pause(); } } m_bSampleSkipped = FALSE;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?