home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / effect.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  20.7 KB  |  724 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. // Base class for simple Effect filter
  13. //
  14.  
  15. #include <streams.h>
  16. #include <initguid.h>
  17. #include <mmsystem.h>
  18. #include <vfw.h>
  19. #include <olectl.h>
  20. #include <olectlid.h>
  21. #include <stdlib.h>
  22.  
  23. #include "ieffect.h"
  24.  
  25. #define _EFFECT_IMPLEMENTATION_
  26. #include "effect.h"
  27. #include "effprop.h"
  28.  
  29. // setup data
  30.  
  31. AMOVIESETUP_MEDIATYPE sudPinTypes =   { &MEDIATYPE_Video                // clsMajorType
  32.                                            , &MEDIASUBTYPE_NULL }  ;       // clsMinorType
  33.  
  34. AMOVIESETUP_PIN psudPins[] = { { L"Input"            // strName
  35.                                , FALSE               // bRendered
  36.                                , FALSE               // bOutput
  37.                                , FALSE               // bZero
  38.                                , FALSE               // bMany
  39.                                , &CLSID_NULL         // clsConnectsToFilter
  40.                                , L"Output"           // strConnectsToPin
  41.                                , 1                   // nTypes
  42.                                , &sudPinTypes }      // lpTypes
  43.  
  44.                              , { L"Input"            // strName
  45.                                , FALSE               // bRendered
  46.                                , FALSE               // bOutput
  47.                                , FALSE               // bZero
  48.                                , FALSE               // bMany
  49.                                , &CLSID_NULL         // clsConnectsToFilter
  50.                                , L"Output"           // strConnectsToPin
  51.                                , 1                   // nTypes
  52.                                , &sudPinTypes }      // lpTypes
  53.  
  54.                              , { L"Output"           // strName
  55.                                , FALSE               // bRendered
  56.                                , TRUE                // bOutput
  57.                                , FALSE               // bZero
  58.                                , FALSE               // bMany
  59.                                , &CLSID_NULL         // clsConnectsToFilter
  60.                                , L"Input"            // strConnectsToPin
  61.                                , 1                   // nTypes
  62.                                , &sudPinTypes } };   // lpTypes
  63.  
  64.  
  65. AMOVIESETUP_FILTER sudEffect = { &CLSID_VideoEffect               // clsID
  66.                                   , L"Video Contrast"               // strName
  67.                                   , MERIT_DO_NOT_USE                // dwMerit
  68.                                   , 3                               // nPins
  69.                                   , psudPins };                     // lpPin
  70.  
  71.  
  72.  
  73. // list of class ids and creator functions for class factory
  74. CFactoryTemplate g_Templates[] = {
  75.     {L"Sample Video Effect", &CLSID_VideoEffect, CEffectFilter::CreateInstance},
  76.     {L"Effect Property Page", &CLSID_EffectPropertyPage, CEffectProperties::CreateInstance}
  77. };
  78. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  79.  
  80. // this goes in the factory template table to create new instances
  81. CUnknown *
  82. CEffectFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT * phr)
  83. {
  84.     return new CEffectFilter(pUnk, phr);
  85. }
  86.  
  87. /* Implements the CEffectFilter class */
  88.  
  89. CEffectFilter::CEffectFilter(
  90.     LPUNKNOWN pUnk,
  91.     HRESULT *phr)
  92.     : CBaseVideoMixer(NAME("Effect Filter"), pUnk, CLSID_VideoEffect, phr, MAXINPUTS),
  93.     CPersistStream(pUnk, phr)
  94. {
  95.     m_effectStart = 0;
  96.     m_effectEnd = 1000;
  97.  
  98.     // !!! registry?
  99.     char   sz[60];
  100.     GetProfileStringA("Quartz", "EffectStart", "20.0", sz, 60);
  101.     m_effectStartTime = COARefTime(atof(sz));
  102.     GetProfileStringA("Quartz", "EffectLength", "10.0", sz, 60);
  103.     m_effectTime = COARefTime(atof(sz));
  104.  
  105.     m_streamOffsets[1] = m_effectStartTime;
  106.     m_streamLengths[0] = m_effectTime + m_effectStartTime;
  107.     m_streamLengths[1] = CRefTime(100000000L); // !!! big number
  108.  
  109.     m_apOffsets = m_streamOffsets;
  110.     m_apLengths = m_streamLengths;
  111.  
  112.     m_bUsingClock = TRUE;
  113.  
  114.     // BIG hack: should be getting this period from one of the input streams,
  115.     // or a dialog box, or something....
  116.     m_iClockPeriod = 1000 / 15; // !!!
  117. }
  118.  
  119. //
  120. // GetSetupData
  121. //
  122. LPAMOVIESETUP_FILTER CEffectFilter::GetSetupData()
  123. {
  124.   return &sudEffect;
  125. }
  126.  
  127. CEffectFilter::~CEffectFilter()
  128. {
  129.     // get the critsec to ensure that all threads have exited
  130.     CAutoLock lock(&m_csFilter);
  131.  
  132. }
  133.     
  134. STDMETHODIMP
  135. CEffectFilter::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
  136. {
  137.  
  138.     if (riid == IID_ISpecifyPropertyPages) {
  139.         return GetInterface((ISpecifyPropertyPages *) this, ppv);
  140.     } else if (riid == IID_IEffect) {
  141.         return GetInterface((IEffect *) this, ppv);
  142.     } else if (riid == IID_IPersistStream) {
  143.     return GetInterface((IPersistStream *) this, ppv);
  144.     }
  145.     else {
  146.     return CBaseVideoMixer::NonDelegatingQueryInterface(riid, ppv);
  147.     }
  148. }
  149.  
  150.  
  151. HRESULT
  152. CEffectFilter::CanMixType(const CMediaType *pmt)
  153. {
  154.     // Firstly, can we mix this video type? We reject everything but
  155.     // non-compressed, fixed size samples.
  156.     if (!IsEqualGUID(*pmt->Type(), MEDIATYPE_Video))
  157.         return VFW_E_INVALIDMEDIATYPE;
  158.  
  159.     if ((*pmt->FormatType() != FORMAT_VideoInfo) || !pmt->IsFixedSize())
  160.         return E_FAIL;
  161.  
  162.     if (pmt->FormatLength() < SIZE_VIDEOHEADER)
  163.     return E_FAIL;
  164.  
  165.     VIDEOINFO *pvi = (VIDEOINFO *) pmt->Format();
  166.  
  167.     if (pvi == NULL)
  168.     return E_FAIL;
  169.  
  170.     if (pvi->bmiHeader.biCompression != BI_RGB &&
  171.         pvi->bmiHeader.biCompression != BI_BITFIELDS)
  172.         return E_INVALIDARG; // !!!
  173.  
  174.     return S_OK;
  175. }
  176.  
  177.  
  178. PVOID getPixelPtr(int x, int y, BYTE *p, BITMAPINFOHEADER *lpbi)
  179. {
  180.     int iBytesPerPixel = lpbi->biBitCount / 8;
  181.     return (PVOID) (p + (y * DIBWIDTHBYTES(*lpbi)) + x * iBytesPerPixel);
  182. }
  183.  
  184. void copyRegion(int x,int y,int width,int height,BYTE *pSource,
  185.         BYTE *pDest, BITMAPINFOHEADER *lpbi)
  186. // blt between two samples of the same size & bit depth at the same x,y location.
  187. {
  188.     int iBytesPerPixel = lpbi->biBitCount / 8;
  189.     int iWidth = lpbi->biWidth;
  190.     long lNumBytes;
  191.     BYTE *pSourceBuffer, *pDestBuffer;
  192.     int line;
  193.  
  194.     // may need to check for non zero DirectX
  195.     // strides in the future.
  196.  
  197.     if ( (width == iWidth) && (height > 1)) // we have a run of full length lines.
  198.     {
  199.     lNumBytes = width * height * iBytesPerPixel;
  200.     pSourceBuffer = (BYTE *) getPixelPtr(x, y, pSource, lpbi);
  201.     pDestBuffer = (BYTE *) getPixelPtr(x, y, pDest, lpbi);
  202.     CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lNumBytes);
  203.     }
  204.     else if ((height > 0) && (width > 0))
  205.     {
  206.     lNumBytes = width * iBytesPerPixel;
  207.     for (line = y ; line < y + height ; line++)
  208.     {
  209.         pSourceBuffer = (BYTE *) getPixelPtr(x, line, pSource, lpbi);
  210.         pDestBuffer = (BYTE *) getPixelPtr(x, line, pDest, lpbi);
  211.         CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lNumBytes);
  212.     }
  213.     }
  214. }
  215.  
  216. void averageLine(int x, int y,long lNumBytes, BYTE *streamA,
  217.          BYTE *streamB, BYTE *streamC,BITMAPINFOHEADER *lpbi)
  218. {
  219.     BYTE *pA, *pB, *pC;
  220.     DWORD *dA, *dB, *dC;
  221.     WORD *wA, *wB, *wC;
  222.     int numDwords;
  223.     int i;
  224.     int iBytesPerPixel = lpbi->biBitCount / 8;
  225.     int iWidth = lpbi->biWidth;
  226.  
  227.     if (lNumBytes < 0L)
  228.     return;
  229.  
  230.     pA = (BYTE *) getPixelPtr(x,y,streamA,lpbi);
  231.     pB = (BYTE *) getPixelPtr(x,y,streamB,lpbi);        
  232.     pC = (BYTE *) getPixelPtr(x,y,streamC,lpbi);
  233.     dA = (DWORD *) pA;
  234.     dB = (DWORD *) pB;
  235.     dC = (DWORD *) pC;
  236.  
  237.     if (iBytesPerPixel == 1) // alternate pixels
  238.     {
  239.     int height, width, xx, yy;
  240.     height = 1;
  241.     if (lNumBytes > (long) iWidth)
  242.         height = (int) (lNumBytes / iWidth);
  243.     width = lNumBytes / height;
  244.     
  245.     for (yy = y ; yy < y + height ; yy++)
  246.     {
  247.         for (xx = x ; xx < x + width ; xx++)
  248.         {
  249.         if ((xx + yy) % 2 == 0)
  250.         {
  251.             *pC++ = *pA++;
  252.             pB++;
  253.         }
  254.         else
  255.         {
  256.             *pC++ = *pB++;
  257.             pA++;
  258.         }
  259.         }
  260.     }
  261.     }
  262.     else if (iBytesPerPixel == 2 && lpbi->biCompression == BI_BITFIELDS)
  263.     // Sleazy algorithm chosen for speed.  Rather than adding two components together
  264.     // and then dividing, we zero out LSB, shift right, and then add.
  265.     {
  266.     numDwords = (int) (lNumBytes / 4);
  267.     for (i = 0; i < numDwords ; i++, dA++, dB++)
  268.         *dC++ = ((*dA & 0xf7def7de) >> 1) + ((*dB & 0xf7def7de) >> 1);
  269.     if ((lNumBytes % 4) == 2L)
  270.     {
  271.         wA = (WORD *) dA;
  272.         wB = (WORD *) dB;
  273.         wC = (WORD *) dC;
  274.         *wC++ = ((*wA & 0xf7de) >> 1) + ((*wB & 0xf7de) >> 1);
  275.     }
  276.     }
  277.     else if (iBytesPerPixel == 2) // RGB555 not 565
  278.     // Sleazy algorithm chosen for speed.  Rather than adding two components together
  279.     // and then dividing, we zero out LSB, shift right, and then add.
  280.     {
  281.     numDwords = (int) (lNumBytes / 4);
  282.     for (i = 0; i < numDwords ; i++, dA++, dB++)
  283.         *dC++ = ((*dA & 0x7bde7bde) >> 1) + ((*dB & 0x7bde7bde) >> 1);
  284.     if ((lNumBytes % 4) == 2L)
  285.     {
  286.         wA = (WORD *) dA;
  287.         wB = (WORD *) dB;
  288.         wC = (WORD *) dC;
  289.         *wC++ = ((*wA & 0x7bde) >> 1) + ((*wB & 0x7bde) >> 1);
  290.     }
  291.     }
  292.     else  // RGB24 or RGB32 - uses sleazy shortcut described above
  293.     {
  294.     numDwords = (int) (lNumBytes / 4);
  295.     for (i = 0; i < numDwords ; i++, dA++, dB++)
  296.         *dC++ = ((*dA & 0xfefefefe) >> 1) + ((*dB & 0xfefefefe) >> 1);
  297.     
  298.     int numBytes = (int) (lNumBytes % 4);
  299.     pA += lNumBytes - numBytes;    
  300.     pB += lNumBytes - numBytes;    
  301.     pC += lNumBytes - numBytes;    
  302.     
  303.     for (i = 0; i < numBytes ; i++, pA++, pB++)
  304.         *pC++ = (*pA >> 1) + (*pB >> 1);
  305.     }
  306. }
  307.  
  308.  
  309. void averageRegion(int x,int y,int width,int height,BYTE *streamA,
  310.            BYTE *streamB, BYTE *streamC, BITMAPINFOHEADER *lpbi)
  311. // Takes two regions A & B, averages them, producing output in C.
  312. // The 3 samples must have the same size & bit depth.  The same x,y location is
  313. // assumed for all 3 samples.
  314. // For 256 colors, alternating pixels are chosen from A & B.
  315. // Supports: RGB32, RGB24, RGB555, & 256 color mode (assuming palette stays fixed)
  316. {
  317.     int iBytesPerPixel = lpbi->biBitCount / 8;
  318.     int iWidth = lpbi->biWidth;
  319.     long lNumBytes;
  320.     int line;
  321.  
  322.     // check for strides in DirectX surfaces in future
  323.     if ( (width == iWidth) && (height > 1)) // we have a run of lines.
  324.     {
  325.     lNumBytes = width * height * iBytesPerPixel;
  326.     averageLine(x,y,lNumBytes, streamA, streamB, streamC, lpbi);
  327.     }
  328.     else if ((height > 0) && (width > 0))
  329.     {
  330.     lNumBytes = width * iBytesPerPixel;
  331.     for (line = 0; line < height; line++, y++)
  332.         averageLine(x,y,lNumBytes, streamA, streamB, streamC, lpbi);
  333.     }
  334. }
  335.  
  336. HRESULT CEffectFilter::ActuallyDoEffect(
  337.         BITMAPINFOHEADER *lpbi,
  338.         LONG lEffectParam,
  339.         BYTE *pIn1,
  340.         BYTE *pIn2,
  341.         BYTE *pOut)
  342. {
  343.     int yActive, xActive;
  344.     int bandHeight;
  345.     int width, height, x, y, xCenter, yCenter;
  346.  
  347.  
  348.     switch (m_effectNum)
  349.     {
  350.     case 0:    //************ WIPE - UP DIRECTION ****************************
  351.         yActive = lpbi->biHeight * lEffectParam / 1000;
  352.         ASSERT(yActive <= lpbi->biHeight);
  353.         copyRegion(0, 0, lpbi->biWidth, yActive, pIn2, pOut, lpbi);
  354.     
  355.         if (yActive < lpbi->biHeight) // anti-alias the edge
  356.         averageRegion(0, yActive, lpbi->biWidth, 1,
  357.                   pIn1, pIn2, pOut, lpbi);
  358.     
  359.         copyRegion(0, yActive+1, lpbi->biWidth,
  360.                lpbi->biHeight - yActive, pIn1, pOut, lpbi);
  361.         break;
  362.     
  363.     case 1: /************************  WIPE - TO THE RIGHT DIRECTION */
  364.         xActive = lpbi->biWidth * lEffectParam / 1000;
  365.         ASSERT(xActive <= lpbi->biWidth);
  366.     
  367.         copyRegion(0, 0, xActive, lpbi->biHeight, pIn2, pOut, lpbi);
  368.         averageRegion(xActive, 0, 1, lpbi->biHeight, pIn1, pIn2, pOut, lpbi);
  369.         copyRegion(xActive+1, 0, lpbi->biWidth - xActive,
  370.                lpbi->biHeight, pIn1, pOut, lpbi);                
  371.         break;
  372.     
  373.     case 2: /****************************** IRIS SQUARE  */
  374.         // will be slightly off-center when dimensions are not even
  375.         xActive = lpbi->biWidth * lEffectParam / 2000;
  376.         yActive = lpbi->biHeight * lEffectParam / 2000;
  377.         xCenter = lpbi->biWidth / 2;
  378.         yCenter = lpbi->biHeight / 2;
  379.     
  380.         if (xActive > 1 && yActive > 1)  // inner solid box for B
  381.         {
  382.         x = xCenter - xActive + 1;
  383.         y = yCenter - yActive + 1;
  384.         
  385.         ASSERT(x >= 0);
  386.         ASSERT(y >= 0);
  387.         width = xActive * 2 - 2;
  388.         height = yActive * 2 - 2;
  389.         
  390.         copyRegion(x, y, width, height, pIn2, pOut, lpbi);
  391.         }
  392.     
  393.         y = yCenter - yActive;
  394.         x = xCenter - xActive;
  395.         width = xActive * 2;
  396.         height = yActive * 2;
  397.     
  398.         // anti-alias the edge box between A & B                
  399.         if (xActive > 0 && yActive > 0 &&
  400.         xActive < xCenter && yActive < yCenter)    
  401.         {
  402.         averageRegion(x, y, width, 1, pIn1, pIn2, pOut, lpbi);
  403.         averageRegion(x, y + 1, 1, height-2, pIn1, pIn2, pOut, lpbi);
  404.         averageRegion(x + width-1, y + 1, 1, height-2, pIn1, pIn2, pOut, lpbi);
  405.         averageRegion(x, y + height-1, width, 1, pIn1, pIn2, pOut, lpbi);
  406.         }
  407.     
  408.     
  409.         // Draw the outer area for A as a series of 4 regions around the edge box                
  410.         if ( (xActive < xCenter - 2) && (yActive < yCenter - 2) )
  411.         {
  412.         copyRegion(0, 0, lpbi->biWidth, y, pIn1, pOut, lpbi);
  413.         copyRegion(0, y, x-1, height, pIn1, pOut, lpbi);
  414.         x = xCenter + xActive;
  415.         copyRegion(x, y, lpbi->biWidth - x + 1, height, pIn1, pOut, lpbi);
  416.         y = yCenter + yActive;
  417.         copyRegion(0, y, lpbi->biWidth, lpbi->biHeight - y - 1,
  418.                pIn1, pOut, lpbi);
  419.         }
  420.         break;
  421.     
  422.     case 3: /************************  BAND MERGE WIPE *****/
  423.         // yActive in range 0 to 1.25 * lpbi->biHeight
  424.         bandHeight = lpbi->biHeight / 4;
  425.         yActive = lEffectParam * (lpbi->biHeight + bandHeight) / 1000;
  426.     
  427.         // bring in B from bottom in clipped range {y = 0 to yActive-bandHeight - 1}
  428.         int lines = yActive - bandHeight;
  429.         copyRegion(0, 0, lpbi->biWidth, lines, pIn2, pOut, lpbi);                                                    
  430.     
  431.         // 50% merge band of A and B in range {yActive - bandHeight to yActive},
  432.         // must be clipped to range {0 to lpbi->biHeight -1}
  433.     
  434.         y = (yActive - bandHeight > 0) ? yActive - bandHeight : 0;
  435.         int yStop = (yActive < lpbi->biHeight - 1) ? yActive : lpbi->biHeight - 1;
  436.         lines = yStop - y + 1;
  437.         averageRegion(0, y, lpbi->biWidth, lines, pIn1, pIn2, pOut, lpbi);
  438.     
  439.         // stream A is at the top until the band runs it over.
  440.         // In clipped range {yActive + 1, lpbi->biHeight - 1}
  441.         lines = lpbi->biHeight - (yActive + 1);
  442.         copyRegion(0, yActive+1, lpbi->biWidth, lines, pIn1, pOut, lpbi);
  443.         break;
  444.     }
  445.     return NOERROR;
  446. }
  447.  
  448. HRESULT
  449. CEffectFilter::MixSamples(IMediaSample *pOutSample)
  450. {
  451.     HRESULT hr = NOERROR;
  452.  
  453.     DbgLog((LOG_TRACE, 8, TEXT("Doing the effect!")));
  454.  
  455.     BYTE *pDataOut;                // Pointer to actual data
  456.  
  457.     pOutSample->GetPointer(&pDataOut);
  458.     ASSERT(pDataOut != NULL);
  459.  
  460.     int    iConnected = 0;
  461.     int size = pOutSample->GetSize();
  462.  
  463.     int effectNow = 1000;  // assume we're finished....
  464.  
  465.     IMediaSample *pSample = NULL;
  466.  
  467.     if (m_apInput[0]->SampleReady())
  468.     pSample = (IMediaSample *) m_apInput[0]->GetHeadSample();
  469.  
  470.     if (pSample != NULL) {
  471.     CRefTime tStart, tStop;
  472.     pSample->GetTime((REFERENCE_TIME *)&tStart,
  473.                          (REFERENCE_TIME *)&tStop);
  474.  
  475.     if (tStart < m_effectStartTime)
  476.         effectNow = 0;
  477.     else
  478.         effectNow = ((tStart.Millisecs() -
  479.                    m_effectStartTime.Millisecs()) * 1000) /
  480.                 max(m_effectTime.Millisecs(), 1);
  481.  
  482.     DbgLog((LOG_TRACE, 8, TEXT("sample %d  start %d  now %d"),
  483.         tStart.Millisecs(),
  484.         m_effectStartTime.Millisecs(), effectNow));
  485.     if (effectNow > 1000)
  486.         effectNow = 1000;
  487.  
  488.     } else {
  489.     ASSERT(m_apInput[0]->m_fEOSReceived);
  490.     }
  491.  
  492.     // if no sample ready on stream 2, what to do?  do effect against
  493.     // blank frame?
  494.     if (m_apInput[1]->SampleReady() && effectNow > 0 && effectNow < 1000) {
  495.     IMediaSample *pSample2 = (IMediaSample *) m_apInput[1]->GetHeadSample();
  496.  
  497.     // scale "effectNow" to be between start & end instead of
  498.     // between 0 and 1000
  499.     effectNow = (effectNow * (m_effectEnd - m_effectStart) / 1000) +
  500.             m_effectStart;
  501.  
  502.     
  503.     BYTE *pData;                // Pointer to actual data
  504.  
  505.     pSample->GetPointer(&pData);
  506.     ASSERT(pData != NULL);
  507.  
  508.     BYTE *pData2;                // Pointer to actual data
  509.  
  510.     pSample2->GetPointer(&pData2);
  511.     ASSERT(pData2 != NULL);
  512.  
  513.     BITMAPINFOHEADER *pbmi = HEADER(m_pOutput->CurrentMediaType().Format());
  514.     hr = ActuallyDoEffect(pbmi, effectNow, pData, pData2, pDataOut);
  515.     } else {
  516.     if (effectNow == 1000 && m_apInput[1]->SampleReady())
  517.         pSample = (IMediaSample *) m_apInput[1]->GetHeadSample();
  518.  
  519.     if (!pSample) {
  520.         DbgLog((LOG_TRACE, 2, TEXT("Odd--nothing to mix!!!")));
  521.         return E_FAIL;
  522.     }
  523.     
  524.     BYTE *pData;                // Pointer to actual data
  525.  
  526.     pSample->GetPointer(&pData);
  527.     ASSERT(pData != NULL);
  528.  
  529.     CopyMemory(pDataOut, pData, size);
  530.     }
  531.  
  532.     return hr;
  533. }
  534.  
  535.  
  536. HRESULT CEffectFilter::SetMediaType(int iPin, const CMediaType *pmt)
  537. {
  538.     HRESULT hr = CBaseVideoMixer::SetMediaType(iPin, pmt);
  539.     if (iPin == m_iInputPinCount) {
  540.     CAutoLock l(&m_csFilter);
  541.  
  542.     DisplayType("SetMediaType (output) ", pmt);
  543.     }
  544.  
  545.     return hr;
  546. }
  547.  
  548.  
  549. //
  550. // --- IEffect ---
  551. //
  552.  
  553.  
  554. STDMETHODIMP CEffectFilter::GetEffectParameters(
  555.     int *effectNum,
  556.     REFTIME *startTime, REFTIME *lengthTime,
  557.     int *startLevel, int *endLevel)
  558. {
  559.     if (effectNum)
  560.     *effectNum = m_effectNum;
  561.  
  562.     if (startLevel)
  563.     *startLevel = m_effectStart;
  564.  
  565.     if (endLevel)
  566.     *endLevel = m_effectEnd;
  567.  
  568.     if (startTime)
  569.     *startTime = COARefTime(m_effectStartTime);
  570.  
  571.     if (lengthTime)
  572.     *lengthTime = COARefTime(m_effectTime);
  573.  
  574.     return NOERROR;
  575. }
  576.  
  577. STDMETHODIMP CEffectFilter::SetEffectParameters(
  578.     int effectNum,
  579.     REFTIME startTime, REFTIME lengthTime,
  580.     int startLevel, int endLevel)
  581. {
  582.     if (effectNum < 0 || effectNum >= NEFFECTS)
  583.     return E_FAIL;
  584.  
  585.     m_effectNum = effectNum;
  586.  
  587.     m_effectStart = startLevel;
  588.     m_effectEnd = endLevel;
  589.  
  590.     m_effectStartTime = COARefTime(startTime);
  591.     m_effectTime = COARefTime(lengthTime);
  592.  
  593.     m_streamOffsets[1] = m_effectStartTime;
  594.     m_streamLengths[0] = m_effectTime + m_effectStartTime;
  595.  
  596.     SetDirty(TRUE);
  597.  
  598.     return NOERROR;
  599. }
  600.  
  601. #if 0
  602. // !!! are we going to add something like this back again?
  603. //
  604. // GetEffectName
  605. //
  606. STDMETHODIMP CEffectFilter::get_EffectName(
  607.     LPOLESTR *EffectName)
  608. {
  609.     if (EffectName) {
  610.     const WCHAR szTitle[] = L"Wipe Effect";
  611.  
  612.     *EffectName = (LPOLESTR) CoTaskMemAlloc(sizeof(szTitle));
  613.  
  614.     if (!*EffectName)
  615.         return E_OUTOFMEMORY;
  616.     
  617.     memcpy(*EffectName, &szTitle, sizeof(szTitle));
  618.     }
  619.  
  620.     return NOERROR;
  621. }
  622. #endif
  623.  
  624.  
  625. //
  626. // --- IPersistStream stuff
  627. //
  628.  
  629. #define WRITEOUT(var)  hr = pStream->Write(&var, sizeof(var), NULL); \
  630.                if (FAILED(hr)) return hr;
  631.  
  632. #define READIN(var)    hr = pStream->Read(&var, sizeof(var), NULL); \
  633.                if (FAILED(hr)) return hr;
  634.  
  635. STDMETHODIMP CEffectFilter::GetClassID(CLSID *pClsid)
  636. {
  637.     *pClsid = CLSID_VideoEffect;
  638.     return NOERROR;
  639. }
  640.  
  641.  
  642. int CEffectFilter::SizeMax()
  643. {
  644.     return
  645.         sizeof(m_effectNum)
  646.       + sizeof(m_effectStart)
  647.       + sizeof(m_effectEnd)
  648.       + sizeof(m_effectStartTime)
  649.       + sizeof(m_effectTime)
  650.     ;
  651.  
  652. }
  653.  
  654.  
  655. HRESULT CEffectFilter::WriteToStream(IStream *pStream)
  656. {
  657.     HRESULT hr;
  658.     WRITEOUT(m_effectNum);
  659.     WRITEOUT(m_effectStart);
  660.     WRITEOUT(m_effectEnd);
  661.     WRITEOUT(m_effectStartTime);
  662.     WRITEOUT(m_effectTime);
  663.     return NOERROR;
  664. }
  665.  
  666.  
  667. HRESULT CEffectFilter::ReadFromStream(IStream *pStream)
  668. {
  669.     HRESULT hr;
  670.     READIN(m_effectNum);
  671.     READIN(m_effectStart);
  672.     READIN(m_effectEnd);
  673.     READIN(m_effectStartTime);
  674.     READIN(m_effectTime);
  675.     return NOERROR;
  676. }
  677.  
  678.  
  679. //
  680. // --- ISpecifyPropertyPages ---
  681. //
  682.  
  683.  
  684. //
  685. // GetPages
  686. //
  687. // Returns the clsid's of the property pages we support
  688. HRESULT CEffectFilter::GetPages(CAUUID *pcauuid) {
  689.     GUID *pguid;
  690.  
  691.     pcauuid->cElems = 1;
  692.     pcauuid->pElems = pguid = (GUID *) CoTaskMemAlloc(sizeof(GUID) * pcauuid->cElems);
  693.  
  694.     if (pcauuid->pElems == NULL)
  695.         return E_OUTOFMEMORY;
  696.  
  697.     *pguid = CLSID_EffectPropertyPage;
  698.  
  699.     return NOERROR;
  700. }
  701.  
  702. /******************************Public*Routine******************************\
  703. * exported entry points for registration and
  704. * unregistration (in this case they only call
  705. * through to default implmentations).
  706. *
  707. *
  708. *
  709. * History:
  710. *
  711. \**************************************************************************/
  712. HRESULT
  713. DllRegisterServer()
  714. {
  715.   return AMovieDllRegisterServer();
  716. }
  717.  
  718. HRESULT
  719. DllUnregisterServer()
  720. {
  721.   return AMovieDllUnregisterServer();
  722. }
  723.  
  724.