summaryrefslogtreecommitdiff
path: root/third_party/BaseClasses/transfrm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/BaseClasses/transfrm.cpp')
-rw-r--r--third_party/BaseClasses/transfrm.cpp1016
1 files changed, 1016 insertions, 0 deletions
diff --git a/third_party/BaseClasses/transfrm.cpp b/third_party/BaseClasses/transfrm.cpp
new file mode 100644
index 00000000..3d170779
--- /dev/null
+++ b/third_party/BaseClasses/transfrm.cpp
@@ -0,0 +1,1016 @@
+//------------------------------------------------------------------------------
+// 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)