From 7873aff384696ef64669c51d0b5457d206536a28 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Thu, 19 Apr 2012 06:36:57 +0000 Subject: Re #1276: Integrate BaseClasses with the project and remove unnecessary classes git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4062 74dad513-b988-da41-8d7b-12977e46ad98 --- third_party/BaseClasses/vtrans.cpp | 468 ------------------------------------- 1 file changed, 468 deletions(-) delete mode 100644 third_party/BaseClasses/vtrans.cpp (limited to 'third_party/BaseClasses/vtrans.cpp') diff --git a/third_party/BaseClasses/vtrans.cpp b/third_party/BaseClasses/vtrans.cpp deleted file mode 100644 index cb4fa998..00000000 --- a/third_party/BaseClasses/vtrans.cpp +++ /dev/null @@ -1,468 +0,0 @@ -//------------------------------------------------------------------------------ -// File: Vtrans.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include -#include -// #include // now in precomp file streams.h - -CVideoTransformFilter::CVideoTransformFilter - ( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid) - : CTransformFilter(pName, pUnk, clsid) - , m_itrLate(0) - , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames - , m_nFramesSinceKeyFrame(0) - , m_bSkipping(FALSE) - , m_tDecodeStart(0) - , m_itrAvgDecode(300000) // 30mSec - probably allows skipping - , m_bQualityChanged(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - - -CVideoTransformFilter::~CVideoTransformFilter() -{ - // nothing to do -} - - -// Reset our quality management state - -HRESULT CVideoTransformFilter::StartStreaming() -{ - m_itrLate = 0; - m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - m_tDecodeStart = 0; - m_itrAvgDecode = 300000; // 30mSec - probably allows skipping - m_bQualityChanged = FALSE; - m_bSampleSkipped = FALSE; - return NOERROR; -} - - -// Overriden to reset quality management information - -HRESULT CVideoTransformFilter::EndFlush() -{ - { - // Synchronize - CAutoLock lck(&m_csReceive); - - // Reset our stats - // - // Note - we don't want to call derived classes here, - // we only want to reset our internal variables and this - // is a convenient way to do it - CVideoTransformFilter::StartStreaming(); - } - return CTransformFilter::EndFlush(); -} - - -HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) -{ - NotifyEvent(EC_ERRORABORT, hr, 0); - m_pOutput->DeliverEndOfStream(); - return hr; -} - - -// Receive() -// -// Accept a sample from upstream, decide whether to process it -// or drop it. If we process it then get a buffer from the -// allocator of the downstream connection, transform it into the -// new buffer and deliver it to the downstream filter. -// If we decide not to process it then we do not get a buffer. - -// Remember that although this code will notice format changes coming into -// the input pin, it will NOT change its output format if that results -// in the filter needing to make a corresponding output format change. Your -// derived filter will have to take care of that. (eg. a palette change if -// the input and output is an 8 bit format). If the input sample is discarded -// and nothing is sent out for this Receive, please remember to put the format -// change on the first output sample that you actually do send. -// If your filter will produce the same output type even when the input type -// changes, then this base class code will do everything you need. - -HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) -{ - // If the next filter downstream is the video renderer, then it may - // be able to operate in DirectDraw mode which saves copying the data - // and gives higher performance. In that case the buffer which we - // get from GetDeliveryBuffer will be a DirectDraw buffer, and - // drawing into this buffer draws directly onto the display surface. - // This means that any waiting for the correct time to draw occurs - // during GetDeliveryBuffer, and that once the buffer is given to us - // the video renderer will count it in its statistics as a frame drawn. - // This means that any decision to drop the frame must be taken before - // calling GetDeliveryBuffer. - - ASSERT(CritCheckIn(&m_csReceive)); - AM_MEDIA_TYPE *pmtOut, *pmt; -#ifdef DEBUG - FOURCCMap fccOut; -#endif - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output pin to deliver to then no point sending us data - ASSERT (m_pOutput != NULL) ; - - // The source filter may dynamically ask us to start transforming from a - // different media type than the one we're using now. If we don't, we'll - // draw garbage. (typically, this is a palette change in the movie, - // but could be something more sinister like the compression type changing, - // or even the video size changing) - -#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource -#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget - - pSample->GetMediaType(&pmt); - if (pmt != NULL && pmt->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); -#ifdef DEBUG - fccOut.SetFOURCC(&pmt->subtype); - LONG lCompression = HEADER(pmt->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmt->pbFormat)->biHeight, - rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pInput->CurrentMediaType() = *pmt; - DeleteMediaType(pmt); - // if this fails, playback will stop, so signal an error - hr = StartStreaming(); - if (FAILED(hr)) { - return AbortPlayback(hr); - } - } - - // Now that we have noticed any format changes on the input sample, it's - // OK to discard it. - - if (ShouldSkipFrame(pSample)) { - MSR_NOTE(m_idSkip); - m_bSampleSkipped = TRUE; - return NOERROR; - } - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - m_bSampleSkipped = FALSE; - - // The renderer may ask us to on-the-fly to start transforming to a - // different format. If we don't obey it, we'll draw garbage - -#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource -#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget - - pOutSample->GetMediaType(&pmtOut); - if (pmtOut != NULL && pmtOut->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); -#ifdef DEBUG - fccOut.SetFOURCC(&pmtOut->subtype); - LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmtOut->pbFormat)->biHeight, - rcT.left, rcT.top, rcT.right, rcT.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS.left, rcS.top, rcS.right, rcS.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pOutput->CurrentMediaType() = *pmtOut; - DeleteMediaType(pmtOut); - hr = StartStreaming(); - - if (SUCCEEDED(hr)) { - // a new format, means a new empty buffer, so wait for a keyframe - // before passing anything on to the renderer. - // !!! a keyframe may never come, so give up after 30 frames - DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); - m_nWaitForKey = 30; - - // if this fails, playback will stop, so signal an error - } else { - - // Must release the sample before calling AbortPlayback - // because we might be holding the win16 lock or - // ddraw lock - pOutSample->Release(); - AbortPlayback(hr); - return hr; - } - } - - // After a discontinuity, we need to wait for the next key frame - if (pSample->IsDiscontinuity() == S_OK) { - DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); - m_nWaitForKey = 30; - } - - // Start timing the transform (and log it if PERF is defined) - - if (SUCCEEDED(hr)) { - m_tDecodeStart = timeGetTime(); - 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); - m_tDecodeStart = timeGetTime()-m_tDecodeStart; - m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); - - // Maybe we're waiting for a keyframe still? - if (m_nWaitForKey) - m_nWaitForKey--; - if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) - m_nWaitForKey = FALSE; - - // if so, then we don't want to pass this on to the renderer - if (m_nWaitForKey && hr == NOERROR) { - DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); - hr = S_FALSE; - } - } - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from video 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.) - // Try not to return S_FALSE to a direct draw buffer (it's wasteful) - // Try to take the decision earlier - before you get it. - - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pOutSample); - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this case 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) { - - // We must Release() the sample before doing anything - // like calling the filter graph because having the - // sample means we may have the DirectDraw lock - // (== win16 lock on some versions) - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - ASSERT(CritCheckIn(&m_csReceive)); - - return hr; -} - - - -BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) -{ - REFERENCE_TIME trStart, trStopAt; - HRESULT hr = pIn->GetTime(&trStart, &trStopAt); - - // Don't skip frames with no timestamps - if (hr != S_OK) - return FALSE; - - int itrFrame = (int)(trStopAt - trStart); // frame duration - - if(S_OK==pIn->IsSyncPoint()) { - MSR_INTEGER(m_idFrameType, 1); - if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { - // record the max - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - } else { - MSR_INTEGER(m_idFrameType, 2); - if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod - && m_nKeyFramePeriod>0 - ) { - // We haven't seen the key frame yet, but we were clearly being - // overoptimistic about how frequent they are. - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - } - - - // Whatever we might otherwise decide, - // if we are taking only a small fraction of the required frame time to decode - // then any quality problems are actually coming from somewhere else. - // Could be a net problem at the source for instance. In this case there's - // no point in us skipping frames here. - if (m_itrAvgDecode*4>itrFrame) { - - // Don't skip unless we are at least a whole frame late. - // (We would skip B frames if more than 1/2 frame late, but they're safe). - if ( m_itrLate > itrFrame ) { - - // Don't skip unless the anticipated key frame would be no more than - // 1 frame early. If the renderer has not been waiting (we *guess* - // it hasn't because we're late) then it will allow frames to be - // played early by up to a frame. - - // Let T = Stream time from now to anticipated next key frame - // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) - // So we skip if T - Late < one frame i.e. - // (duration) * (freq - FramesSince) - Late < duration - // or (duration) * (freq - FramesSince - 1) < Late - - // We don't dare skip until we have seen some key frames and have - // some idea how often they occur and they are reasonably frequent. - if (m_nKeyFramePeriod>0) { - // It would be crazy - but we could have a stream with key frames - // a very long way apart - and if they are further than about - // 3.5 minutes apart then we could get arithmetic overflow in - // reference time units. Therefore we switch to mSec at this point - int it = (itrFrame/10000) - * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); - MSR_INTEGER(m_idTimeTillKey, it); - - // For debug - might want to see the details - dump them as scratch pad -#ifdef VTRANSPERF - MSR_INTEGER(0, itrFrame); - MSR_INTEGER(0, m_nFramesSinceKeyFrame); - MSR_INTEGER(0, m_nKeyFramePeriod); -#endif - if (m_itrLate/10000 > it) { - m_bSkipping = TRUE; - // Now we are committed. Once we start skipping, we - // cannot stop until we hit a key frame. - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777770); // not near enough to next key -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777771); // Next key not predictable -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777772); // Less than one frame late - MSR_INTEGER(0, m_itrLate); - MSR_INTEGER(0, itrFrame); -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping - MSR_INTEGER(0, m_itrAvgDecode); - MSR_INTEGER(0, itrFrame); -#endif - } - - ++m_nFramesSinceKeyFrame; - - if (m_bSkipping) { - // We will count down the lateness as we skip each frame. - // We re-assess each frame. The key frame might not arrive when expected. - // We reset m_itrLate if we get a new Quality message, but actually that's - // not likely because we're not sending frames on to the Renderer. In - // fact if we DID get another one it would mean that there's a long - // pipe between us and the renderer and we might need an altogether - // better strategy to avoid hunting! - m_itrLate = m_itrLate - itrFrame; - } - - MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are - if (m_bSkipping) { - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - } - return m_bSkipping; -} - - -HRESULT CVideoTransformFilter::AlterQuality(Quality q) -{ - // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. - // +, -, >, == etc are not too bad, but * and / are painful. - if (m_itrLate>300000000) { - // Avoid overflow and silliness - more than 30 secs late is already silly - m_itrLate = 300000000; - } else { - m_itrLate = (int)q.Late; - } - // We ignore the other fields - - // We're actually not very good at handling this. In non-direct draw mode - // most of the time can be spent in the renderer which can skip any frame. - // In that case we'd rather the renderer handled things. - // Nevertheless we will keep an eye on it and if we really start getting - // a very long way behind then we will actually skip - but we'll still tell - // the renderer (or whoever is downstream) that they should handle quality. - - return E_FAIL; // Tell the renderer to do his thing. - -} - - - -// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 -#pragma warning(disable:4514) - -- cgit v1.2.3