home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / vtrans.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-26  |  16.6 KB  |  449 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11.  
  12. #include <streams.h>
  13. #include <measure.h>
  14. // #include <vtransfr.h>         // now in precomp file streams.h
  15.  
  16. CVideoTransformFilter::CVideoTransformFilter
  17.     ( TCHAR *pName, LPUNKNOWN pUnk, CLSID clsid, HRESULT *phr)
  18.     : CTransformFilter(pName, pUnk, clsid, phr)
  19.     , m_itrLate(0)
  20.     , m_nKeyFramePeriod(0)      // No QM until we see at least 2 key frames
  21.     , m_nFramesSinceKeyFrame(0)
  22.     , m_bSkipping(FALSE)
  23.     , m_tDecodeStart(0)
  24.     , m_itrAvgDecode(300000)    // 30mSec - probably allows skipping
  25.     , m_bQualityChanged(FALSE)
  26. {
  27.     ASSERT(phr);
  28. #ifdef PERF
  29.     RegisterPerfId();
  30. #endif //  PERF
  31. }
  32.  
  33.  
  34. CVideoTransformFilter::~CVideoTransformFilter()
  35. {
  36.   // nothing to do
  37. }
  38.  
  39.  
  40. // Reset our quality management state
  41.  
  42. HRESULT CVideoTransformFilter::StartStreaming()
  43. {
  44.     m_itrLate = 0;
  45.     m_nKeyFramePeriod = 0;       // No QM until we see at least 2 key frames
  46.     m_nFramesSinceKeyFrame = 0;
  47.     m_bSkipping = FALSE;
  48.     m_tDecodeStart = 0;
  49.     m_itrAvgDecode = 300000;     // 30mSec - probably allows skipping
  50.     m_bQualityChanged = FALSE;
  51.     m_bSampleSkipped = FALSE;
  52.     return NOERROR;
  53. }
  54.  
  55.  
  56. // Overriden to reset quality management information
  57.  
  58. HRESULT CVideoTransformFilter::BeginFlush()
  59. {
  60.     HRESULT hr = StartStreaming();
  61.     if (FAILED(hr)) {
  62.         return hr;
  63.     }
  64.     return CTransformFilter::BeginFlush();
  65. }
  66.  
  67.  
  68. // Receive()
  69. //
  70. // Accept a sample from upstream, decide whether to process it
  71. // or drop it.  If we process it then get a buffer from the
  72. // allocator of the downstream connection, transform it into the
  73. // new buffer and deliver it to the downstream filter.
  74. // If we decide not to process it then we do not get a buffer.
  75.  
  76. HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample)
  77. {
  78.     // If the next filter downstream is the video renderer, then it may
  79.     // be able to operate in DirectDraw mode which saves copying the data
  80.     // and gives higher performance.  In that case the buffer which we
  81.     // get from GetDeliveryBuffer will be a DirectDraw buffer, and
  82.     // drawing into this buffer draws directly onto the display surface.
  83.     // This means that any waiting for the correct time to draw occurs
  84.     // during GetDeliveryBuffer, and that once the buffer is given to us
  85.     // the video renderer will count it in its statistics as a frame drawn.
  86.     // This means that any decision to drop the frame must be taken before
  87.     // calling GetDeliveryBuffer.
  88.  
  89.     AM_MEDIA_TYPE *pmtOut, *pmt;
  90.     FOURCCMap fccOut;
  91.     HRESULT hr;
  92.     ASSERT(pSample);
  93.     IMediaSample * pOutSample;
  94.  
  95.     // If no output pin to deliver to then no point sending us data
  96.     ASSERT (m_pOutput != NULL) ;
  97.  
  98.     if (ShouldSkipFrame(pSample)) {
  99.         MSR_NOTE(m_idSkip);
  100.         m_bSampleSkipped = TRUE;
  101.         return NOERROR;
  102.     }
  103.  
  104.     REFERENCE_TIME tStart, tStop;
  105.     REFERENCE_TIME * pStart = NULL;
  106.     REFERENCE_TIME * pStop = NULL;
  107.  
  108.     if (NOERROR == pSample->GetTime(&tStart, &tStop)) {
  109.     pStart = &tStart;
  110.     pStop  = &tStop;
  111.     }
  112.  
  113.     DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0;
  114.     // This will prevent the image renderer from switching us to DirectDraw
  115.     // when we can't do it without skipping frames because we're not on a
  116.     // keyframe.  If it really has to switch us, it still will, but then we
  117.     // will have to wait for the next keyframe
  118.     if (pSample->IsSyncPoint() != S_OK) {
  119.     dwFlags |= AM_GBF_NOTASYNCPOINT;
  120.     }
  121.  
  122.     // this may block for an indeterminate amount of time
  123.     hr = m_pOutput->GetDeliveryBuffer( &pOutSample
  124.                                      , pStart
  125.                                      , pStop
  126.                                      , dwFlags
  127.                                      );
  128.     if (FAILED(hr)) {
  129.         return hr;
  130.     }
  131.  
  132.     ASSERT(pOutSample);
  133.     pOutSample->SetTime(pStart, pStop);
  134.     pOutSample->SetSyncPoint(pSample->IsSyncPoint() == S_OK);
  135.     pOutSample->SetDiscontinuity(m_bSampleSkipped);
  136.  
  137.     m_bSampleSkipped = FALSE;
  138.  
  139.     // Copy the media times
  140.  
  141.     LONGLONG MediaStart, MediaEnd;
  142.     if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
  143.         pOutSample->SetMediaTime(&MediaStart,&MediaEnd);
  144.     }
  145.  
  146.     // The source filter may dynamically ask us to start transforming from a
  147.     // different media type than the one we're using now.  If we don't, we'll
  148.     // draw garbage. (typically, this is a palette change in the movie,
  149.     // but could be something more sinister like the compression type changing,
  150.     // or even the video size changing)
  151.  
  152. #define rcS1 ((VIDEOINFO *)(pmt->pbFormat))->rcSource
  153. #define rcT1 ((VIDEOINFO *)(pmt->pbFormat))->rcTarget
  154.  
  155.     pSample->GetMediaType(&pmt);
  156.     if (pmt != NULL && pmt->pbFormat != NULL) {
  157.  
  158.     // spew some debug output
  159.     ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL));
  160.         fccOut.SetFOURCC(&pmt->subtype);
  161.     LONG lCompression = HEADER(pmt->pbFormat)->biCompression;
  162.     LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount;
  163.     LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8;
  164.     lStride = (lStride + 3) & ~3;
  165.         DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to")));
  166.         DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
  167.         fccOut.GetFOURCC(), lCompression, lBitCount));
  168.         DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
  169.         HEADER(pmt->pbFormat)->biHeight,
  170.         rcT1.left, rcT1.top, rcT1.right, rcT1.bottom));
  171.         DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
  172.         rcS1.left, rcS1.top, rcS1.right, rcS1.bottom,
  173.         lStride));
  174.  
  175.     // now switch to using the new format.  I am assuming that the
  176.     // derived filter will do the right thing when its media type is
  177.     // switched and streaming is restarted.
  178.  
  179.     m_csFilter.Lock();    // take the filter lock.  Don't let anybody else
  180.                 // call StartStreaming or we'll end up thinking
  181.                 // we're streaming the old data and not the new
  182.                 // format we've just been given!
  183.     StopStreaming();
  184.     m_pInput->CurrentMediaType() = *pmt;
  185.     DeleteMediaType(pmt);
  186.     // not much we can do if this fails
  187.     hr = StartStreaming();
  188.     m_csFilter.Unlock();
  189.     }
  190.  
  191.     // The renderer may ask us to on-the-fly to start transforming to a
  192.     // different format.  If we don't obey it, we'll draw garbage
  193.  
  194. #define rcS ((VIDEOINFO *)(pmtOut->pbFormat))->rcSource
  195. #define rcT ((VIDEOINFO *)(pmtOut->pbFormat))->rcTarget
  196.  
  197.     pOutSample->GetMediaType(&pmtOut);
  198.     if (pmtOut != NULL && pmtOut->pbFormat != NULL) {
  199.  
  200.     // spew some debug output
  201.     ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL));
  202.         fccOut.SetFOURCC(&pmtOut->subtype);
  203.     LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression;
  204.     LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount;
  205.     LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8;
  206.     lStride = (lStride + 3) & ~3;
  207.         DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to")));
  208.         DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
  209.         fccOut.GetFOURCC(), lCompression, lBitCount));
  210.         DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
  211.         HEADER(pmtOut->pbFormat)->biHeight,
  212.         rcT.left, rcT.top, rcT.right, rcT.bottom));
  213.         DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
  214.         rcS.left, rcS.top, rcS.right, rcS.bottom,
  215.         lStride));
  216.  
  217.     // now switch to using the new format.  I am assuming that the
  218.     // derived filter will do the right thing when its media type is
  219.     // switched and streaming is restarted.
  220.  
  221.     m_csFilter.Lock();    // take the filter lock.  Don't let anybody else
  222.                 // call StartStreaming or we'll end up thinking
  223.                 // we're streaming the old data and not the new
  224.                 // format we've just been given!
  225.     StopStreaming();
  226.     m_pOutput->CurrentMediaType() = *pmtOut;
  227.     DeleteMediaType(pmtOut);
  228.     hr = StartStreaming();
  229.     m_csFilter.Unlock();
  230.  
  231.     if (SUCCEEDED(hr)) {
  232.          // a new format, means a new empty buffer, so wait for a keyframe
  233.         // before passing anything on to the renderer.
  234.         // !!! a keyframe may never come, so give up after 30 frames
  235.             DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe")));
  236.         m_nWaitForKey = 30;
  237.     }
  238.     }
  239.  
  240.     // Start timing the transform (and log it if PERF is defined)
  241.  
  242.     if (SUCCEEDED(hr)) {
  243.         m_tDecodeStart = timeGetTime();
  244.         MSR_START(m_idTransform);
  245.  
  246.         // have the derived class transform the data
  247.         hr = Transform(pSample, pOutSample);
  248.  
  249.         // Stop the clock (and log it if PERF is defined)
  250.         MSR_STOP(m_idTransform);
  251.         m_tDecodeStart = timeGetTime()-m_tDecodeStart;
  252.         m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16);
  253.  
  254.         // Maybe we're waiting for a keyframe still?
  255.         if (m_nWaitForKey)
  256.             m_nWaitForKey--;
  257.         if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK)
  258.         m_nWaitForKey = FALSE;
  259.  
  260.         // if so, then we don't want to pass this on to the renderer
  261.         if (m_nWaitForKey && hr == NOERROR) {
  262.             DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe")));
  263.         hr = S_FALSE;
  264.     }
  265.     }
  266.  
  267.     if (FAILED(hr)) {
  268.         DbgLog((LOG_TRACE,1,TEXT("Error from video transform")));
  269.     } else {
  270.         // the Transform() function can return S_FALSE to indicate that the
  271.         // sample should not be delivered; we only deliver the sample if it's
  272.         // really S_OK (same as NOERROR, of course.)
  273.         // Try not to return S_FALSE to a direct draw buffer (it's wasteful)
  274.         // Try to take the decision earlier - before you get it.
  275.  
  276.         if (hr == NOERROR) {
  277.             hr = m_pOutput->Deliver(pOutSample);
  278.         } else {
  279.             // S_FALSE returned from Transform is a PRIVATE agreement
  280.             // We should return NOERROR from Receive() in this case because returning S_FALSE
  281.             // from Receive() means that this is the end of the stream and no more data should
  282.             // be sent.
  283.             if (S_FALSE == hr) {
  284.                 m_bSampleSkipped = TRUE;
  285.                 if (!m_bQualityChanged) {
  286.                     m_bQualityChanged = TRUE;
  287.                     NotifyEvent(EC_QUALITY_CHANGE,0,0);
  288.                 }
  289.                 hr = NOERROR;
  290.             }
  291.         }
  292.     }
  293.  
  294.     // release the output buffer. If the connected pin still needs it,
  295.     // it will have addrefed it itself.
  296.     pOutSample->Release();
  297.  
  298.     return hr;
  299. }
  300.  
  301.  
  302.  
  303. BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn)
  304. {
  305.     REFERENCE_TIME trStart, trStopAt;
  306.     pIn->GetTime(&trStart, &trStopAt);
  307.     int itrFrame = (int)(trStopAt - trStart);  // frame duration
  308.  
  309.     if(S_OK==pIn->IsSyncPoint()) {
  310.         MSR_INTEGER(m_idFrameType, 1);
  311.         if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) {
  312.             // record the max
  313.             m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
  314.         }
  315.         m_nFramesSinceKeyFrame = 0;
  316.         m_bSkipping = FALSE;
  317.     } else {
  318.         MSR_INTEGER(m_idFrameType, 2);
  319.         if (  m_nFramesSinceKeyFrame>m_nKeyFramePeriod
  320.            && m_nKeyFramePeriod>0
  321.            ) {
  322.             // We haven't seen the key frame yet, but we were clearly being
  323.             // overoptimistic about how frequent they are.
  324.             m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
  325.         }
  326.     }
  327.  
  328.  
  329.     // Whatever we might otherwise decide,
  330.     // if we are taking only a small fraction of the required frame time to decode
  331.     // then any quality problems are actually coming from somewhere else.
  332.     // Could be a net problem at the source for instance.  In this case there's
  333.     // no point in us skipping frames here.
  334.     if (m_itrAvgDecode*4>itrFrame) {
  335.  
  336.         // Don't skip unless we are at least a whole frame late.
  337.         // (We would skip B frames if more than 1/2 frame late, but they're safe).
  338.         if ( m_itrLate > itrFrame ) {
  339.  
  340.             // Don't skip unless the anticipated key frame would be no more than
  341.             // 1 frame early.  If the renderer has not been waiting (we *guess*
  342.             // it hasn't because we're late) then it will allow frames to be
  343.             // played early by up to a frame.
  344.  
  345.             // Let T = Stream time from now to anticipated next key frame
  346.             // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame)
  347.             // So we skip if T - Late < one frame  i.e.
  348.             //   (duration) * (freq - FramesSince) - Late < duration
  349.             // or (duration) * (freq - FramesSince - 1) < Late
  350.  
  351.             // We don't dare skip until we have seen some key frames and have
  352.             // some idea how often they occur and they are reasonably frequent.
  353.             if (m_nKeyFramePeriod>0) {
  354.                 // It would be crazy - but we could have a stream with key frames
  355.                 // a very long way apart - and if they are further than about
  356.                 // 3.5 minutes apart then we could get arithmetic overflow in
  357.                 // reference time units.  Therefore we switch to mSec at this point
  358.                 int it = (itrFrame/10000)
  359.                          * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame -  1);
  360.                 MSR_INTEGER(m_idTimeTillKey, it);
  361.  
  362.                 // For debug - might want to see the details - dump them as scratch pad
  363. #ifdef VTRANSPERF
  364.                 MSR_INTEGER(0, itrFrame);
  365.                 MSR_INTEGER(0, m_nFramesSinceKeyFrame);
  366.                 MSR_INTEGER(0, m_nKeyFramePeriod);
  367. #endif
  368.                 if (m_itrLate/10000 > it) {
  369.                     m_bSkipping = TRUE;
  370.                     // Now we are committed.  Once we start skipping, we
  371.                     // cannot stop until we hit a key frame.
  372.                 } else {
  373. #ifdef VTRANSPERF
  374.                     MSR_INTEGER(0, 777770);  // not near enough to next key
  375. #endif
  376.                 }
  377.             } else {
  378. #ifdef VTRANSPERF
  379.                 MSR_INTEGER(0, 777771);  // Next key not predictable
  380. #endif
  381.             }
  382.         } else {
  383. #ifdef VTRANSPERF
  384.             MSR_INTEGER(0, 777772);  // Less than one frame late
  385.             MSR_INTEGER(0, m_itrLate);
  386.             MSR_INTEGER(0, itrFrame);
  387. #endif
  388.         }
  389.     } else {
  390. #ifdef VTRANSPERF
  391.         MSR_INTEGER(0, 777773);  // Decode time short - not not worth skipping
  392.         MSR_INTEGER(0, m_itrAvgDecode);
  393.         MSR_INTEGER(0, itrFrame);
  394. #endif
  395.     }
  396.  
  397.     ++m_nFramesSinceKeyFrame;
  398.  
  399.     if (m_bSkipping) {
  400.         // We will count down the lateness as we skip each frame.
  401.         // We re-assess each frame.  The key frame might not arrive when expected.
  402.         // We reset m_itrLate if we get a new Quality message, but actually that's
  403.         // not likely because we're not sending frames on to the Renderer.  In
  404.         // fact if we DID get another one it would mean that there's a long
  405.         // pipe between us and the renderer and we might need an altogether
  406.         // better strategy to avoid hunting!
  407.         m_itrLate = m_itrLate - itrFrame;
  408.     }
  409.  
  410.     MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are
  411.     if (m_bSkipping) {
  412.         if (!m_bQualityChanged) {
  413.             m_bQualityChanged = TRUE;
  414.             NotifyEvent(EC_QUALITY_CHANGE,0,0);
  415.         }
  416.     }
  417.     return m_bSkipping;
  418. }
  419.  
  420.  
  421. HRESULT CVideoTransformFilter::AlterQuality(Quality q)
  422. {
  423.     // to reduce the amount of 64 bit arithmetic, m_itrLate is an int.
  424.     // +, -, >, == etc  are not too bad, but * and / are painful.
  425.     if (m_itrLate>300000000) {
  426.         // Avoid overflow and silliness - more than 30 secs late is already silly
  427.         m_itrLate = 300000000;
  428.     } else {
  429.         m_itrLate = (int)q.Late;
  430.     }
  431.     // We ignore the other fields
  432.  
  433.     // We're actually not very good at handling this.  In non-direct draw mode
  434.     // most of the time can be spent in the renderer which can skip any frame.
  435.     // In that case we'd rather the renderer handled things.
  436.     // Nevertheless we will keep an eye on it and if we really start getting
  437.     // a very long way behind then we will actually skip - but we'll still tell
  438.     // the renderer (or whoever is downstream) that they should handle quality.
  439.  
  440.     return E_FAIL;     // Tell the renderer to do his thing.
  441.  
  442. }
  443.  
  444.  
  445.  
  446. // This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4
  447. #pragma warning(disable:4514)
  448.  
  449.