12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016 |
- //------------------------------------------------------------------------------
- // File: Transfrm.cpp
- //
- // Desc: DirectShow base classes - implements class for simple transform
- // filters such as video decompressors.
- //
- // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
- #include <streams.h>
- #include <measure.h>
- // =================================================================
- // Implements the CTransformFilter class
- // =================================================================
- CTransformFilter::CTransformFilter(__in_opt LPCTSTR pName,
- __inout_opt 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
- }
- #ifdef UNICODE
- CTransformFilter::CTransformFilter(__in_opt LPCSTR pName,
- __inout_opt 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
- }
- #endif
- // destructor
- CTransformFilter::~CTransformFilter()
- {
- // Delete the pins
- delete m_pInput;
- delete m_pOutput;
- }
- // Transform place holder - should never be called
- HRESULT 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 provide
- int 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, __deref_out 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.
- HRESULT
- CTransformFilter::StartStreaming()
- {
- return NOERROR;
- }
- HRESULT
- CTransformFilter::StopStreaming()
- {
- return NOERROR;
- }
- // override this to grab extra interfaces on connection
- HRESULT
- CTransformFilter::CheckConnect(PIN_DIRECTION dir, IPin *pPin)
- {
- UNREFERENCED_PARAMETER(dir);
- UNREFERENCED_PARAMETER(pPin);
- return NOERROR;
- }
- // place holder to allow derived classes to release any extra interfaces
- HRESULT
- CTransformFilter::BreakConnect(PIN_DIRECTION dir)
- {
- UNREFERENCED_PARAMETER(dir);
- return NOERROR;
- }
- // Let derived classes know about connection completion
- HRESULT
- CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin)
- {
- UNREFERENCED_PARAMETER(direction);
- UNREFERENCED_PARAMETER(pReceivePin);
- return NOERROR;
- }
- // override this to know when the media type is really set
- HRESULT
- CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
- {
- UNREFERENCED_PARAMETER(direction);
- UNREFERENCED_PARAMETER(pmt);
- return NOERROR;
- }
- // Set up our output sample
- HRESULT
- CTransformFilter::InitializeOutputSample(IMediaSample *pSample, __deref_out 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 process
- HRESULT
- CTransformFilter::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 sent
- HRESULT
- CTransformFilter::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 thread
- HRESULT
- CTransformFilter::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 thread
- HRESULT
- CTransformFilter::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 them
- STDMETHODIMP
- CTransformFilter::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_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;
- }
- STDMETHODIMP
- CTransformFilter::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_csReceive);
- hr = StartStreaming();
- }
- if (SUCCEEDED(hr)) {
- hr = CBaseFilter::Pause();
- }
- }
- m_bSampleSkipped = FALSE;
- m_bQualityChanged = FALSE;
- return hr;
- }
- HRESULT
- CTransformFilter::NewSegment(
- REFERENCE_TIME tStart,
- REFERENCE_TIME tStop,
- double dRate)
- {
- if (m_pOutput != NULL) {
- return m_pOutput->DeliverNewSegment(tStart, tStop, dRate);
- }
- return S_OK;
- }
- // Check streaming status
- HRESULT
- CTransformInputPin::CheckStreaming()
- {
- ASSERT(m_pTransformFilter->m_pOutput != NULL);
- if (!m_pTransformFilter->m_pOutput->IsConnected()) {
- return VFW_E_NOT_CONNECTED;
- } else {
- // Shouldn't be able to get any data if we're not connected!
- ASSERT(IsConnected());
- // we're flushing
- if (m_bFlushing) {
- return S_FALSE;
- }
- // Don't process stuff in Stopped state
- if (IsStopped()) {
- return VFW_E_WRONG_STATE;
- }
- if (m_bRunTimeError) {
- return VFW_E_RUNTIME_ERROR;
- }
- return S_OK;
- }
- }
- // =================================================================
- // Implements the CTransformInputPin class
- // =================================================================
- // constructor
- CTransformInputPin::CTransformInputPin(
- __in_opt LPCTSTR pObjectName,
- __inout CTransformFilter *pTransformFilter,
- __inout HRESULT * phr,
- __in_opt LPCWSTR pName)
- : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
- m_pTransformFilter = pTransformFilter;
- }
- #ifdef UNICODE
- CTransformInputPin::CTransformInputPin(
- __in_opt LPCSTR pObjectName,
- __inout CTransformFilter *pTransformFilter,
- __inout HRESULT * phr,
- __in_opt LPCWSTR pName)
- : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
- m_pTransformFilter = pTransformFilter;
- }
- #endif
- // provides derived filter a chance to grab extra interfaces
- HRESULT
- CTransformInputPin::CheckConnect(IPin *pPin)
- {
- HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin);
- if (FAILED(hr)) {
- return hr;
- }
- return CBaseInputPin::CheckConnect(pPin);
- }
- // provides derived filter a chance to release it's extra interfaces
- HRESULT
- CTransformInputPin::BreakConnect()
- {
- // Can't disconnect unless stopped
- ASSERT(IsStopped());
- m_pTransformFilter->BreakConnect(PINDIR_INPUT);
- return CBaseInputPin::BreakConnect();
- }
- // Let derived class know when the input pin is connected
- HRESULT
- CTransformInputPin::CompleteConnect(IPin *pReceivePin)
- {
- HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
- if (FAILED(hr)) {
- return hr;
- }
- return CBaseInputPin::CompleteConnect(pReceivePin);
- }
- // check that we can support a given media type
- HRESULT
- CTransformInputPin::CheckMediaType(const CMediaType* pmt)
- {
- // Check the input type
- HRESULT hr = m_pTransformFilter->CheckInputType(pmt);
- if (S_OK != hr) {
- return hr;
- }
- // if the output pin is still connected, then we have
- // to check the transform not just the input format
- if ((m_pTransformFilter->m_pOutput != NULL) &&
- (m_pTransformFilter->m_pOutput->IsConnected())) {
- return m_pTransformFilter->CheckTransform(
- pmt,
- &m_pTransformFilter->m_pOutput->CurrentMediaType());
- } else {
- return hr;
- }
- }
- // set the media type for this connection
- HRESULT
- CTransformInputPin::SetMediaType(const CMediaType* mtIn)
- {
- // Set the base class media type (should always succeed)
- HRESULT hr = CBasePin::SetMediaType(mtIn);
- if (FAILED(hr)) {
- return hr;
- }
- // check the transform can be done (should always succeed)
- ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn)));
- return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn);
- }
- // =================================================================
- // Implements IMemInputPin interface
- // =================================================================
- // provide EndOfStream that passes straight downstream
- // (there is no queued data)
- STDMETHODIMP
- CTransformInputPin::EndOfStream(void)
- {
- CAutoLock lck(&m_pTransformFilter->m_csReceive);
- HRESULT hr = CheckStreaming();
- if (S_OK == hr) {
- hr = m_pTransformFilter->EndOfStream();
- }
- return hr;
- }
- // enter flushing state. Call default handler to block Receives, then
- // pass to overridable method in filter
- STDMETHODIMP
- CTransformInputPin::BeginFlush(void)
- {
- CAutoLock lck(&m_pTransformFilter->m_csFilter);
- // Are we actually doing anything?
- ASSERT(m_pTransformFilter->m_pOutput != NULL);
- if (!IsConnected() ||
- !m_pTransformFilter->m_pOutput->IsConnected()) {
- return VFW_E_NOT_CONNECTED;
- }
- HRESULT hr = CBaseInputPin::BeginFlush();
- if (FAILED(hr)) {
- return hr;
- }
- return m_pTransformFilter->BeginFlush();
- }
- // leave flushing state.
- // Pass to overridable method in filter, then call base class
- // to unblock receives (finally)
- STDMETHODIMP
- CTransformInputPin::EndFlush(void)
- {
- CAutoLock lck(&m_pTransformFilter->m_csFilter);
- // Are we actually doing anything?
- ASSERT(m_pTransformFilter->m_pOutput != NULL);
- if (!IsConnected() ||
- !m_pTransformFilter->m_pOutput->IsConnected()) {
- return VFW_E_NOT_CONNECTED;
- }
- HRESULT hr = m_pTransformFilter->EndFlush();
- if (FAILED(hr)) {
- return hr;
- }
- return CBaseInputPin::EndFlush();
- }
- // here's the next block of data from the stream.
- // AddRef it yourself if you need to hold it beyond the end
- // of this call.
- HRESULT
- CTransformInputPin::Receive(IMediaSample * pSample)
- {
- HRESULT hr;
- CAutoLock lck(&m_pTransformFilter->m_csReceive);
- ASSERT(pSample);
- // check all is well with the base class
- hr = CBaseInputPin::Receive(pSample);
- if (S_OK == hr) {
- hr = m_pTransformFilter->Receive(pSample);
- }
- return hr;
- }
- // override to pass downstream
- STDMETHODIMP
- CTransformInputPin::NewSegment(
- REFERENCE_TIME tStart,
- REFERENCE_TIME tStop,
- double dRate)
- {
- // Save the values in the pin
- CBasePin::NewSegment(tStart, tStop, dRate);
- return m_pTransformFilter->NewSegment(tStart, tStop, dRate);
- }
- // =================================================================
- // Implements the CTransformOutputPin class
- // =================================================================
- // constructor
- CTransformOutputPin::CTransformOutputPin(
- __in_opt LPCTSTR pObjectName,
- __inout CTransformFilter *pTransformFilter,
- __inout HRESULT * phr,
- __in_opt LPCWSTR pPinName)
- : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
- m_pPosition(NULL)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
- m_pTransformFilter = pTransformFilter;
- }
- #ifdef UNICODE
- CTransformOutputPin::CTransformOutputPin(
- __in_opt LPCSTR pObjectName,
- __inout CTransformFilter *pTransformFilter,
- __inout HRESULT * phr,
- __in_opt LPCWSTR pPinName)
- : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
- m_pPosition(NULL)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
- m_pTransformFilter = pTransformFilter;
- }
- #endif
- // destructor
- CTransformOutputPin::~CTransformOutputPin()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin")));
- if (m_pPosition) m_pPosition->Release();
- }
- // overriden to expose IMediaPosition and IMediaSeeking control interfaces
- STDMETHODIMP
- CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
- {
- CheckPointer(ppv,E_POINTER);
- ValidateReadWritePtr(ppv,sizeof(PVOID));
- *ppv = NULL;
- if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
- // we should have an input pin by now
- ASSERT(m_pTransformFilter->m_pInput != NULL);
- if (m_pPosition == NULL) {
- HRESULT hr = CreatePosPassThru(
- GetOwner(),
- FALSE,
- (IPin *)m_pTransformFilter->m_pInput,
- &m_pPosition);
- if (FAILED(hr)) {
- return hr;
- }
- }
- return m_pPosition->QueryInterface(riid, ppv);
- } else {
- return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
- }
- }
- // provides derived filter a chance to grab extra interfaces
- HRESULT
- CTransformOutputPin::CheckConnect(IPin *pPin)
- {
- // we should have an input connection first
- ASSERT(m_pTransformFilter->m_pInput != NULL);
- if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
- return E_UNEXPECTED;
- }
- HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin);
- if (FAILED(hr)) {
- return hr;
- }
- return CBaseOutputPin::CheckConnect(pPin);
- }
- // provides derived filter a chance to release it's extra interfaces
- HRESULT
- CTransformOutputPin::BreakConnect()
- {
- // Can't disconnect unless stopped
- ASSERT(IsStopped());
- m_pTransformFilter->BreakConnect(PINDIR_OUTPUT);
- return CBaseOutputPin::BreakConnect();
- }
- // Let derived class know when the output pin is connected
- HRESULT
- CTransformOutputPin::CompleteConnect(IPin *pReceivePin)
- {
- HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
- if (FAILED(hr)) {
- return hr;
- }
- return CBaseOutputPin::CompleteConnect(pReceivePin);
- }
- // check a given transform - must have selected input type first
- HRESULT
- CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut)
- {
- // must have selected input first
- ASSERT(m_pTransformFilter->m_pInput != NULL);
- if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
- return E_INVALIDARG;
- }
- return m_pTransformFilter->CheckTransform(
- &m_pTransformFilter->m_pInput->CurrentMediaType(),
- pmtOut);
- }
- // called after we have agreed a media type to actually set it in which case
- // we run the CheckTransform function to get the output format type again
- HRESULT
- CTransformOutputPin::SetMediaType(const CMediaType* pmtOut)
- {
- HRESULT hr = NOERROR;
- ASSERT(m_pTransformFilter->m_pInput != NULL);
- ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid());
- // Set the base class media type (should always succeed)
- hr = CBasePin::SetMediaType(pmtOut);
- if (FAILED(hr)) {
- return hr;
- }
- #ifdef DEBUG
- if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter->
- m_pInput->CurrentMediaType(),pmtOut))) {
- DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type")));
- DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope")));
- DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input.")));
- }
- #endif
- return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut);
- }
- // pass the buffer size decision through to the main transform class
- HRESULT
- CTransformOutputPin::DecideBufferSize(
- IMemAllocator * pAllocator,
- __inout ALLOCATOR_PROPERTIES* pProp)
- {
- return m_pTransformFilter->DecideBufferSize(pAllocator, pProp);
- }
- // return a specific media type indexed by iPosition
- HRESULT
- CTransformOutputPin::GetMediaType(
- int iPosition,
- __inout CMediaType *pMediaType)
- {
- ASSERT(m_pTransformFilter->m_pInput != NULL);
- // We don't have any media types if our input is not connected
- if (m_pTransformFilter->m_pInput->IsConnected()) {
- return m_pTransformFilter->GetMediaType(iPosition,pMediaType);
- } else {
- return VFW_S_NO_MORE_ITEMS;
- }
- }
- // Override this if you can do something constructive to act on the
- // quality message. Consider passing it upstream as well
- // Pass the quality mesage on upstream.
- STDMETHODIMP
- CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q)
- {
- UNREFERENCED_PARAMETER(pSender);
- ValidateReadPtr(pSender,sizeof(IBaseFilter));
- // First see if we want to handle this ourselves
- HRESULT hr = m_pTransformFilter->AlterQuality(q);
- if (hr!=S_FALSE) {
- return hr; // either S_OK or a failure
- }
- // S_FALSE means we pass the message on.
- // Find the quality sink for our input pin and send it there
- ASSERT(m_pTransformFilter->m_pInput != NULL);
- return m_pTransformFilter->m_pInput->PassNotify(q);
- } // Notify
- // the following removes a very large number of level 4 warnings from the microsoft
- // compiler output, which are not useful at all in this case.
- #pragma warning(disable:4514)
|