A Fast Bresenham Type Algorithm For Drawing Ellipses by John Kennedy
[xy_vsfilter.git] / src / filters / BaseClasses / transfrm.cpp
blob1ed90cc12d9fd7ce8003cd58fbd26586769e7865
1 //------------------------------------------------------------------------------
2 // File: Transfrm.cpp
3 //
4 // Desc: DirectShow base classes - implements class for simple transform
5 // filters such as video decompressors.
6 //
7 // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
11 #include <streams.h>
12 #include <measure.h>
15 // =================================================================
16 // Implements the CTransformFilter class
17 // =================================================================
19 CTransformFilter::CTransformFilter(TCHAR *pName,
20 LPUNKNOWN pUnk,
21 REFCLSID clsid) :
22 CBaseFilter(pName,pUnk,&m_csFilter, clsid),
23 m_pInput(NULL),
24 m_pOutput(NULL),
25 m_bEOSDelivered(FALSE),
26 m_bQualityChanged(FALSE),
27 m_bSampleSkipped(FALSE)
29 #ifdef PERF
30 RegisterPerfId();
31 #endif // PERF
34 #ifdef UNICODE
35 CTransformFilter::CTransformFilter(char *pName,
36 LPUNKNOWN pUnk,
37 REFCLSID clsid) :
38 CBaseFilter(pName,pUnk,&m_csFilter, clsid),
39 m_pInput(NULL),
40 m_pOutput(NULL),
41 m_bEOSDelivered(FALSE),
42 m_bQualityChanged(FALSE),
43 m_bSampleSkipped(FALSE)
45 #ifdef PERF
46 RegisterPerfId();
47 #endif // PERF
49 #endif
51 // destructor
53 CTransformFilter::~CTransformFilter()
55 // Delete the pins
57 delete m_pInput;
58 delete m_pOutput;
62 // Transform place holder - should never be called
63 HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut)
65 UNREFERENCED_PARAMETER(pIn);
66 UNREFERENCED_PARAMETER(pOut);
67 DbgBreak("CTransformFilter::Transform() should never be called");
68 return E_UNEXPECTED;
72 // return the number of pins we provide
74 int CTransformFilter::GetPinCount()
76 return 2;
80 // return a non-addrefed CBasePin * for the user to addref if he holds onto it
81 // for longer than his pointer to us. We create the pins dynamically when they
82 // are asked for rather than in the constructor. This is because we want to
83 // give the derived class an oppportunity to return different pin objects
85 // We return the objects as and when they are needed. If either of these fails
86 // then we return NULL, the assumption being that the caller will realise the
87 // whole deal is off and destroy us - which in turn will delete everything.
89 CBasePin *
90 CTransformFilter::GetPin(int n)
92 HRESULT hr = S_OK;
94 // Create an input pin if necessary
96 if (m_pInput == NULL) {
98 m_pInput = new CTransformInputPin(NAME("Transform input pin"),
99 this, // Owner filter
100 &hr, // Result code
101 L"XForm In"); // Pin name
104 // Can't fail
105 ASSERT(SUCCEEDED(hr));
106 if (m_pInput == NULL) {
107 return NULL;
109 m_pOutput = (CTransformOutputPin *)
110 new CTransformOutputPin(NAME("Transform output pin"),
111 this, // Owner filter
112 &hr, // Result code
113 L"XForm Out"); // Pin name
116 // Can't fail
117 ASSERT(SUCCEEDED(hr));
118 if (m_pOutput == NULL) {
119 delete m_pInput;
120 m_pInput = NULL;
124 // Return the appropriate pin
126 if (n == 0) {
127 return m_pInput;
128 } else
129 if (n == 1) {
130 return m_pOutput;
131 } else {
132 return NULL;
138 // FindPin
140 // If Id is In or Out then return the IPin* for that pin
141 // creating the pin if need be. Otherwise return NULL with an error.
143 STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin)
145 CheckPointer(ppPin,E_POINTER);
146 ValidateReadWritePtr(ppPin,sizeof(IPin *));
148 if (0==lstrcmpW(Id,L"In")) {
149 *ppPin = GetPin(0);
150 } else if (0==lstrcmpW(Id,L"Out")) {
151 *ppPin = GetPin(1);
152 } else {
153 *ppPin = NULL;
154 return VFW_E_NOT_FOUND;
157 HRESULT hr = NOERROR;
158 // AddRef() returned pointer - but GetPin could fail if memory is low.
159 if (*ppPin) {
160 (*ppPin)->AddRef();
161 } else {
162 hr = E_OUTOFMEMORY; // probably. There's no pin anyway.
164 return hr;
168 // override these two functions if you want to inform something
169 // about entry to or exit from streaming state.
171 HRESULT
172 CTransformFilter::StartStreaming()
174 return NOERROR;
178 HRESULT
179 CTransformFilter::StopStreaming()
181 return NOERROR;
185 // override this to grab extra interfaces on connection
187 HRESULT
188 CTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin)
190 UNREFERENCED_PARAMETER(dir);
191 UNREFERENCED_PARAMETER(pPin);
192 return NOERROR;
196 // place holder to allow derived classes to release any extra interfaces
198 HRESULT
199 CTransformFilter::BreakConnect(PIN_DIRECTION dir)
201 UNREFERENCED_PARAMETER(dir);
202 return NOERROR;
206 // Let derived classes know about connection completion
208 HRESULT
209 CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin)
211 UNREFERENCED_PARAMETER(direction);
212 UNREFERENCED_PARAMETER(pReceivePin);
213 return NOERROR;
217 // override this to know when the media type is really set
219 HRESULT
220 CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
222 UNREFERENCED_PARAMETER(direction);
223 UNREFERENCED_PARAMETER(pmt);
224 return NOERROR;
228 // Set up our output sample
229 HRESULT
230 CTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample)
232 IMediaSample *pOutSample;
234 // default - times are the same
236 AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
237 DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0;
239 // This will prevent the image renderer from switching us to DirectDraw
240 // when we can't do it without skipping frames because we're not on a
241 // keyframe. If it really has to switch us, it still will, but then we
242 // will have to wait for the next keyframe
243 if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) {
244 dwFlags |= AM_GBF_NOTASYNCPOINT;
247 ASSERT(m_pOutput->m_pAllocator != NULL);
248 HRESULT hr = m_pOutput->m_pAllocator->GetBuffer(
249 &pOutSample
250 , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ?
251 &pProps->tStart : NULL
252 , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ?
253 &pProps->tStop : NULL
254 , dwFlags
256 *ppOutSample = pOutSample;
257 if (FAILED(hr)) {
258 return hr;
261 ASSERT(pOutSample);
262 IMediaSample2 *pOutSample2;
263 if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2,
264 (void **)&pOutSample2))) {
265 /* Modify it */
266 AM_SAMPLE2_PROPERTIES OutProps;
267 EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(
268 FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps)
270 OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
271 OutProps.dwSampleFlags =
272 (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) |
273 (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED);
274 OutProps.tStart = pProps->tStart;
275 OutProps.tStop = pProps->tStop;
276 OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId);
277 hr = pOutSample2->SetProperties(
278 FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId),
279 (PBYTE)&OutProps
281 if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) {
282 m_bSampleSkipped = FALSE;
284 pOutSample2->Release();
285 } else {
286 if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) {
287 pOutSample->SetTime(&pProps->tStart,
288 &pProps->tStop);
290 if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) {
291 pOutSample->SetSyncPoint(TRUE);
293 if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) {
294 pOutSample->SetDiscontinuity(TRUE);
295 m_bSampleSkipped = FALSE;
297 // Copy the media times
299 LONGLONG MediaStart, MediaEnd;
300 if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
301 pOutSample->SetMediaTime(&MediaStart,&MediaEnd);
304 return S_OK;
307 // override this to customize the transform process
309 HRESULT
310 CTransformFilter::Receive(IMediaSample *pSample)
312 /* Check for other streams and pass them on */
313 AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
314 if (pProps->dwStreamId != AM_STREAM_MEDIA) {
315 return m_pOutput->m_pInputPin->Receive(pSample);
317 HRESULT hr;
318 ASSERT(pSample);
319 IMediaSample * pOutSample;
321 // If no output to deliver to then no point sending us data
323 ASSERT (m_pOutput != NULL) ;
325 // Set up the output sample
326 hr = InitializeOutputSample(pSample, &pOutSample);
328 if (FAILED(hr)) {
329 return hr;
332 // Start timing the transform (if PERF is defined)
333 MSR_START(m_idTransform);
335 // have the derived class transform the data
337 hr = Transform(pSample, pOutSample);
339 // Stop the clock and log it (if PERF is defined)
340 MSR_STOP(m_idTransform);
342 if (FAILED(hr)) {
343 DbgLog((LOG_TRACE,1,TEXT("Error from transform")));
344 } else {
345 // the Transform() function can return S_FALSE to indicate that the
346 // sample should not be delivered; we only deliver the sample if it's
347 // really S_OK (same as NOERROR, of course.)
348 if (hr == NOERROR) {
349 hr = m_pOutput->m_pInputPin->Receive(pOutSample);
350 m_bSampleSkipped = FALSE; // last thing no longer dropped
351 } else {
352 // S_FALSE returned from Transform is a PRIVATE agreement
353 // We should return NOERROR from Receive() in this cause because returning S_FALSE
354 // from Receive() means that this is the end of the stream and no more data should
355 // be sent.
356 if (S_FALSE == hr) {
358 // Release the sample before calling notify to avoid
359 // deadlocks if the sample holds a lock on the system
360 // such as DirectDraw buffers do
361 pOutSample->Release();
362 m_bSampleSkipped = TRUE;
363 if (!m_bQualityChanged) {
364 NotifyEvent(EC_QUALITY_CHANGE,0,0);
365 m_bQualityChanged = TRUE;
367 return NOERROR;
372 // release the output buffer. If the connected pin still needs it,
373 // it will have addrefed it itself.
374 pOutSample->Release();
376 return hr;
380 // Return S_FALSE to mean "pass the note on upstream"
381 // Return NOERROR (Same as S_OK)
382 // to mean "I've done something about it, don't pass it on"
383 HRESULT CTransformFilter::AlterQuality(Quality q)
385 UNREFERENCED_PARAMETER(q);
386 return S_FALSE;
390 // EndOfStream received. Default behaviour is to deliver straight
391 // downstream, since we have no queued data. If you overrode Receive
392 // and have queue data, then you need to handle this and deliver EOS after
393 // all queued data is sent
394 HRESULT
395 CTransformFilter::EndOfStream(void)
397 HRESULT hr = NOERROR;
398 if (m_pOutput != NULL) {
399 hr = m_pOutput->DeliverEndOfStream();
402 return hr;
406 // enter flush state. Receives already blocked
407 // must override this if you have queued data or a worker thread
408 HRESULT
409 CTransformFilter::BeginFlush(void)
411 HRESULT hr = NOERROR;
412 if (m_pOutput != NULL) {
413 // block receives -- done by caller (CBaseInputPin::BeginFlush)
415 // discard queued data -- we have no queued data
417 // free anyone blocked on receive - not possible in this filter
419 // call downstream
420 hr = m_pOutput->DeliverBeginFlush();
422 return hr;
426 // leave flush state. must override this if you have queued data
427 // or a worker thread
428 HRESULT
429 CTransformFilter::EndFlush(void)
431 // sync with pushing thread -- we have no worker thread
433 // ensure no more data to go downstream -- we have no queued data
435 // call EndFlush on downstream pins
436 ASSERT (m_pOutput != NULL);
437 return m_pOutput->DeliverEndFlush();
439 // caller (the input pin's method) will unblock Receives
443 // override these so that the derived filter can catch them
445 STDMETHODIMP
446 CTransformFilter::Stop()
448 CAutoLock lck1(&m_csFilter);
449 if (m_State == State_Stopped) {
450 return NOERROR;
453 // Succeed the Stop if we are not completely connected
455 ASSERT(m_pInput == NULL || m_pOutput != NULL);
456 if (m_pInput == NULL || m_pInput->IsConnected() == FALSE ||
457 m_pOutput->IsConnected() == FALSE) {
458 m_State = State_Stopped;
459 m_bEOSDelivered = FALSE;
460 return NOERROR;
463 ASSERT(m_pInput);
464 ASSERT(m_pOutput);
466 // decommit the input pin before locking or we can deadlock
467 m_pInput->Inactive();
469 // synchronize with Receive calls
471 CAutoLock lck2(&m_csReceive);
472 m_pOutput->Inactive();
474 // allow a class derived from CTransformFilter
475 // to know about starting and stopping streaming
477 HRESULT hr = StopStreaming();
478 if (SUCCEEDED(hr)) {
479 // complete the state transition
480 m_State = State_Stopped;
481 m_bEOSDelivered = FALSE;
483 return hr;
487 STDMETHODIMP
488 CTransformFilter::Pause()
490 CAutoLock lck(&m_csFilter);
491 HRESULT hr = NOERROR;
493 if (m_State == State_Paused) {
494 // (This space left deliberately blank)
497 // If we have no input pin or it isn't yet connected then when we are
498 // asked to pause we deliver an end of stream to the downstream filter.
499 // This makes sure that it doesn't sit there forever waiting for
500 // samples which we cannot ever deliver without an input connection.
502 else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) {
503 if (m_pOutput && m_bEOSDelivered == FALSE) {
504 m_pOutput->DeliverEndOfStream();
505 m_bEOSDelivered = TRUE;
507 m_State = State_Paused;
510 // We may have an input connection but no output connection
511 // However, if we have an input pin we do have an output pin
513 else if (m_pOutput->IsConnected() == FALSE) {
514 m_State = State_Paused;
517 else {
518 if (m_State == State_Stopped) {
519 // allow a class derived from CTransformFilter
520 // to know about starting and stopping streaming
521 CAutoLock lck2(&m_csReceive);
522 hr = StartStreaming();
524 if (SUCCEEDED(hr)) {
525 hr = CBaseFilter::Pause();
529 m_bSampleSkipped = FALSE;
530 m_bQualityChanged = FALSE;
531 return hr;
534 HRESULT
535 CTransformFilter::NewSegment(
536 REFERENCE_TIME tStart,
537 REFERENCE_TIME tStop,
538 double dRate)
540 if (m_pOutput != NULL) {
541 return m_pOutput->DeliverNewSegment(tStart, tStop, dRate);
543 return S_OK;
546 // Check streaming status
547 HRESULT
548 CTransformInputPin::CheckStreaming()
550 ASSERT(m_pTransformFilter->m_pOutput != NULL);
551 if (!m_pTransformFilter->m_pOutput->IsConnected()) {
552 return VFW_E_NOT_CONNECTED;
553 } else {
554 // Shouldn't be able to get any data if we're not connected!
555 ASSERT(IsConnected());
557 // we're flushing
558 if (m_bFlushing) {
559 return S_FALSE;
561 // Don't process stuff in Stopped state
562 if (IsStopped()) {
563 return VFW_E_WRONG_STATE;
565 if (m_bRunTimeError) {
566 return VFW_E_RUNTIME_ERROR;
568 return S_OK;
573 // =================================================================
574 // Implements the CTransformInputPin class
575 // =================================================================
578 // constructor
580 CTransformInputPin::CTransformInputPin(
581 TCHAR *pObjectName,
582 CTransformFilter *pTransformFilter,
583 HRESULT * phr,
584 LPCWSTR pName)
585 : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
587 DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
588 m_pTransformFilter = pTransformFilter;
591 #ifdef UNICODE
592 CTransformInputPin::CTransformInputPin(
593 CHAR *pObjectName,
594 CTransformFilter *pTransformFilter,
595 HRESULT * phr,
596 LPCWSTR pName)
597 : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
599 DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
600 m_pTransformFilter = pTransformFilter;
602 #endif
604 // provides derived filter a chance to grab extra interfaces
606 HRESULT
607 CTransformInputPin::CheckConnect(IPin *pPin)
609 HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin);
610 if (FAILED(hr)) {
611 return hr;
613 return CBaseInputPin::CheckConnect(pPin);
617 // provides derived filter a chance to release it's extra interfaces
619 HRESULT
620 CTransformInputPin::BreakConnect()
622 // Can't disconnect unless stopped
623 ASSERT(IsStopped());
624 m_pTransformFilter->BreakConnect(PINDIR_INPUT);
625 return CBaseInputPin::BreakConnect();
629 // Let derived class know when the input pin is connected
631 HRESULT
632 CTransformInputPin::CompleteConnect(IPin *pReceivePin)
634 HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
635 if (FAILED(hr)) {
636 return hr;
638 return CBaseInputPin::CompleteConnect(pReceivePin);
642 // check that we can support a given media type
644 HRESULT
645 CTransformInputPin::CheckMediaType(const CMediaType* pmt)
647 // Check the input type
649 HRESULT hr = m_pTransformFilter->CheckInputType(pmt);
650 if (S_OK != hr) {
651 return hr;
654 // if the output pin is still connected, then we have
655 // to check the transform not just the input format
657 if ((m_pTransformFilter->m_pOutput != NULL) &&
658 (m_pTransformFilter->m_pOutput->IsConnected())) {
659 return m_pTransformFilter->CheckTransform(
660 pmt,
661 &m_pTransformFilter->m_pOutput->CurrentMediaType());
662 } else {
663 return hr;
668 // set the media type for this connection
670 HRESULT
671 CTransformInputPin::SetMediaType(const CMediaType* mtIn)
673 // Set the base class media type (should always succeed)
674 HRESULT hr = CBasePin::SetMediaType(mtIn);
675 if (FAILED(hr)) {
676 return hr;
679 // check the transform can be done (should always succeed)
680 ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn)));
682 return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn);
686 // =================================================================
687 // Implements IMemInputPin interface
688 // =================================================================
691 // provide EndOfStream that passes straight downstream
692 // (there is no queued data)
693 STDMETHODIMP
694 CTransformInputPin::EndOfStream(void)
696 CAutoLock lck(&m_pTransformFilter->m_csReceive);
697 HRESULT hr = CheckStreaming();
698 if (S_OK == hr) {
699 hr = m_pTransformFilter->EndOfStream();
701 return hr;
705 // enter flushing state. Call default handler to block Receives, then
706 // pass to overridable method in filter
707 STDMETHODIMP
708 CTransformInputPin::BeginFlush(void)
710 CAutoLock lck(&m_pTransformFilter->m_csFilter);
711 // Are we actually doing anything?
712 ASSERT(m_pTransformFilter->m_pOutput != NULL);
713 if (!IsConnected() ||
714 !m_pTransformFilter->m_pOutput->IsConnected()) {
715 return VFW_E_NOT_CONNECTED;
717 HRESULT hr = CBaseInputPin::BeginFlush();
718 if (FAILED(hr)) {
719 return hr;
722 return m_pTransformFilter->BeginFlush();
726 // leave flushing state.
727 // Pass to overridable method in filter, then call base class
728 // to unblock receives (finally)
729 STDMETHODIMP
730 CTransformInputPin::EndFlush(void)
732 CAutoLock lck(&m_pTransformFilter->m_csFilter);
733 // Are we actually doing anything?
734 ASSERT(m_pTransformFilter->m_pOutput != NULL);
735 if (!IsConnected() ||
736 !m_pTransformFilter->m_pOutput->IsConnected()) {
737 return VFW_E_NOT_CONNECTED;
740 HRESULT hr = m_pTransformFilter->EndFlush();
741 if (FAILED(hr)) {
742 return hr;
745 return CBaseInputPin::EndFlush();
749 // here's the next block of data from the stream.
750 // AddRef it yourself if you need to hold it beyond the end
751 // of this call.
753 HRESULT
754 CTransformInputPin::Receive(IMediaSample * pSample)
756 HRESULT hr;
757 CAutoLock lck(&m_pTransformFilter->m_csReceive);
758 ASSERT(pSample);
760 // check all is well with the base class
761 hr = CBaseInputPin::Receive(pSample);
762 if (S_OK == hr) {
763 hr = m_pTransformFilter->Receive(pSample);
765 return hr;
771 // override to pass downstream
772 STDMETHODIMP
773 CTransformInputPin::NewSegment(
774 REFERENCE_TIME tStart,
775 REFERENCE_TIME tStop,
776 double dRate)
778 // Save the values in the pin
779 CBasePin::NewSegment(tStart, tStop, dRate);
780 return m_pTransformFilter->NewSegment(tStart, tStop, dRate);
786 // =================================================================
787 // Implements the CTransformOutputPin class
788 // =================================================================
791 // constructor
793 CTransformOutputPin::CTransformOutputPin(
794 TCHAR *pObjectName,
795 CTransformFilter *pTransformFilter,
796 HRESULT * phr,
797 LPCWSTR pPinName)
798 : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
799 m_pPosition(NULL)
801 DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
802 m_pTransformFilter = pTransformFilter;
806 #ifdef UNICODE
807 CTransformOutputPin::CTransformOutputPin(
808 CHAR *pObjectName,
809 CTransformFilter *pTransformFilter,
810 HRESULT * phr,
811 LPCWSTR pPinName)
812 : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
813 m_pPosition(NULL)
815 DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
816 m_pTransformFilter = pTransformFilter;
819 #endif
821 // destructor
823 CTransformOutputPin::~CTransformOutputPin()
825 DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin")));
827 if (m_pPosition) m_pPosition->Release();
831 // overriden to expose IMediaPosition and IMediaSeeking control interfaces
833 STDMETHODIMP
834 CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
836 CheckPointer(ppv,E_POINTER);
837 ValidateReadWritePtr(ppv,sizeof(PVOID));
838 *ppv = NULL;
840 if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
842 // we should have an input pin by now
844 ASSERT(m_pTransformFilter->m_pInput != NULL);
846 if (m_pPosition == NULL) {
848 HRESULT hr = CreatePosPassThru(
849 GetOwner(),
850 FALSE,
851 (IPin *)m_pTransformFilter->m_pInput,
852 &m_pPosition);
853 if (FAILED(hr)) {
854 return hr;
857 return m_pPosition->QueryInterface(riid, ppv);
858 } else {
859 return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
864 // provides derived filter a chance to grab extra interfaces
866 HRESULT
867 CTransformOutputPin::CheckConnect(IPin *pPin)
869 // we should have an input connection first
871 ASSERT(m_pTransformFilter->m_pInput != NULL);
872 if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
873 return E_UNEXPECTED;
876 HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin);
877 if (FAILED(hr)) {
878 return hr;
880 return CBaseOutputPin::CheckConnect(pPin);
884 // provides derived filter a chance to release it's extra interfaces
886 HRESULT
887 CTransformOutputPin::BreakConnect()
889 // Can't disconnect unless stopped
890 ASSERT(IsStopped());
891 m_pTransformFilter->BreakConnect(PINDIR_OUTPUT);
892 return CBaseOutputPin::BreakConnect();
896 // Let derived class know when the output pin is connected
898 HRESULT
899 CTransformOutputPin::CompleteConnect(IPin *pReceivePin)
901 HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
902 if (FAILED(hr)) {
903 return hr;
905 return CBaseOutputPin::CompleteConnect(pReceivePin);
909 // check a given transform - must have selected input type first
911 HRESULT
912 CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut)
914 // must have selected input first
915 ASSERT(m_pTransformFilter->m_pInput != NULL);
916 if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
917 return E_INVALIDARG;
920 return m_pTransformFilter->CheckTransform(
921 &m_pTransformFilter->m_pInput->CurrentMediaType(),
922 pmtOut);
926 // called after we have agreed a media type to actually set it in which case
927 // we run the CheckTransform function to get the output format type again
929 HRESULT
930 CTransformOutputPin::SetMediaType(const CMediaType* pmtOut)
932 HRESULT hr = NOERROR;
933 ASSERT(m_pTransformFilter->m_pInput != NULL);
935 ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid());
937 // Set the base class media type (should always succeed)
938 hr = CBasePin::SetMediaType(pmtOut);
939 if (FAILED(hr)) {
940 return hr;
943 #ifdef DEBUG
944 if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter->
945 m_pInput->CurrentMediaType(),pmtOut))) {
946 DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type")));
947 DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope")));
948 DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input.")));
950 #endif
952 return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut);
956 // pass the buffer size decision through to the main transform class
958 HRESULT
959 CTransformOutputPin::DecideBufferSize(
960 IMemAllocator * pAllocator,
961 ALLOCATOR_PROPERTIES* pProp)
963 return m_pTransformFilter->DecideBufferSize(pAllocator, pProp);
968 // return a specific media type indexed by iPosition
970 HRESULT
971 CTransformOutputPin::GetMediaType(
972 int iPosition,
973 CMediaType *pMediaType)
975 ASSERT(m_pTransformFilter->m_pInput != NULL);
977 // We don't have any media types if our input is not connected
979 if (m_pTransformFilter->m_pInput->IsConnected()) {
980 return m_pTransformFilter->GetMediaType(iPosition,pMediaType);
981 } else {
982 return VFW_S_NO_MORE_ITEMS;
987 // Override this if you can do something constructive to act on the
988 // quality message. Consider passing it upstream as well
990 // Pass the quality mesage on upstream.
992 STDMETHODIMP
993 CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q)
995 UNREFERENCED_PARAMETER(pSender);
996 ValidateReadPtr(pSender,sizeof(IBaseFilter));
998 // First see if we want to handle this ourselves
999 HRESULT hr = m_pTransformFilter->AlterQuality(q);
1000 if (hr!=S_FALSE) {
1001 return hr; // either S_OK or a failure
1004 // S_FALSE means we pass the message on.
1005 // Find the quality sink for our input pin and send it there
1007 ASSERT(m_pTransformFilter->m_pInput != NULL);
1009 return m_pTransformFilter->m_pInput->PassNotify(q);
1011 } // Notify
1014 // the following removes a very large number of level 4 warnings from the microsoft
1015 // compiler output, which are not useful at all in this case.
1016 #pragma warning(disable:4514)