home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / contrast.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  15.6 KB  |  620 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. // Contrast
  13. //
  14. // A Transform filter that alters the contrast of a video
  15. // image as it passes through
  16.  
  17. #include <windows.h>
  18. #include <streams.h>
  19.  
  20. #include <initguid.h>
  21. #include <olectl.h>
  22. #include <olectlid.h>
  23.  
  24. #include "contuids.h"
  25. #include "icontrst.h"
  26. #include "contprop.h"
  27. #include "contrast.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.                              , { L"Output"           // strName
  44.                                , FALSE               // bRendered
  45.                                , TRUE                // bOutput
  46.                                , FALSE               // bZero
  47.                                , FALSE               // bMany
  48.                                , &CLSID_NULL         // clsConnectsToFilter
  49.                                , L"Input"            // strConnectsToPin
  50.                                , 1                   // nTypes
  51.                                , &sudPinTypes } };   // lpTypes
  52.  
  53.  
  54. AMOVIESETUP_FILTER sudContrast = { &CLSID_Contrast                  // clsID
  55.                                   , L"Video Contrast"               // strName
  56.                                   , MERIT_DO_NOT_USE                // dwMerit
  57.                                   , 2                               // nPins
  58.                                   , psudPins };                     // lpPin
  59.  
  60.  
  61.  
  62. // COM Global table of objects in this dll
  63. CFactoryTemplate g_Templates[2] = {
  64.  
  65.     {L"Video Contrast", &CLSID_Contrast, CContrast::CreateInstance},
  66.     {L"Video Contrast Property Page", &CLSID_ContrastPropertyPage, CContrastProperties::CreateInstance}
  67. };
  68. // Count of objects listed in g_cTemplates
  69. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  70.  
  71.  
  72. //
  73. // CContrast::Constructor
  74. //
  75. CContrast::CContrast(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)
  76.     : CTransformFilter(tszName, punk, CLSID_Contrast, phr)
  77.     , m_DefaultContrastLevel(0)
  78.     , m_ContrastLevel(m_DefaultContrastLevel)
  79.     , m_PrevLevel(m_ContrastLevel)
  80.     , m_lBufferRequest(1) {
  81.  
  82. }
  83.  
  84.  
  85. //
  86. // CreateInstance
  87. //
  88. // Provide the way for COM to create a CContrast object
  89. CUnknown *CContrast::CreateInstance(LPUNKNOWN punk, HRESULT *phr) {
  90.  
  91.     CContrast *pNewObject = new CContrast(NAME("Contrast Transform Filter"), punk, phr);
  92.     if (pNewObject == NULL) {
  93.         *phr = E_OUTOFMEMORY;
  94.     }
  95.  
  96.     return pNewObject;
  97.  
  98. }
  99.  
  100.  
  101. //
  102. // GetSetupData
  103. //
  104. LPAMOVIESETUP_FILTER CContrast::GetSetupData()
  105. {
  106.   return &sudContrast;
  107. }
  108.  
  109. //
  110. // NonDelegatingQueryInterface
  111. //
  112. // Reveals IContrast & ISpecifyPropertyPages
  113. STDMETHODIMP CContrast::NonDelegatingQueryInterface(REFIID riid, void ** ppv) {
  114.  
  115.     if (riid == IID_IContrast) {
  116.         return GetInterface((IContrast *) this, ppv);
  117.     }
  118.     else if (riid == IID_ISpecifyPropertyPages) {
  119.         return GetInterface((ISpecifyPropertyPages *) this, ppv);
  120.     }
  121.     else {
  122.         return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
  123.     }
  124. }
  125.  
  126.  
  127. //
  128. // Transform
  129. //
  130. // Copy the input sample into thee output sample. Then transform
  131. // the output sample 'in place'.
  132. HRESULT CContrast::Transform(IMediaSample *pIn, IMediaSample *pOut) {
  133.  
  134.     HRESULT hr = Copy(pIn, pOut);
  135.     if (FAILED(hr)) {
  136.         return hr;
  137.     }
  138.  
  139.     return Transform(pOut);
  140. }
  141.  
  142.  
  143. //
  144. // Copy
  145. //
  146. // make Dest an identical copy of Source
  147. HRESULT CContrast::Copy(IMediaSample *pSource, IMediaSample *pDest) const {
  148.  
  149.     {
  150.     // Copy the sample data
  151.  
  152.     BYTE *pSourceBuffer, *pDestBuffer;
  153.     long lSourceSize = pSource->GetActualDataLength();
  154.     long lDestSize    = pDest->GetSize();
  155.  
  156.     ASSERT(lDestSize >= lSourceSize);
  157.  
  158.     pSource->GetPointer(&pSourceBuffer);
  159.     pDest->GetPointer(&pDestBuffer);
  160.  
  161.     CopyMemory( (PVOID) pDestBuffer
  162.               , (PVOID) pSourceBuffer
  163.               , lSourceSize
  164.               );
  165.     }
  166.     {
  167.     // Copy the sample times
  168.  
  169.     REFERENCE_TIME TimeStart, TimeEnd;
  170.     if (NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) {
  171.         pDest->SetTime(&TimeStart, &TimeEnd);
  172.     }
  173.  
  174.         LONGLONG MediaStart, MediaEnd;
  175.         if (pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
  176.             pDest->SetMediaTime(&MediaStart,&MediaEnd);
  177.         }
  178.     }
  179.     {
  180.     // Copy the Sync point property
  181.  
  182.     HRESULT hr = pSource->IsSyncPoint();
  183.     if (hr == S_OK) {
  184.         pDest->SetSyncPoint(TRUE);
  185.     }
  186.     else if (hr == S_FALSE) {
  187.         pDest->SetSyncPoint(FALSE);
  188.     }
  189.     else {    // an unexpected error has occured...
  190.         return E_UNEXPECTED;
  191.     }
  192.     }
  193.     {
  194.     // Copy the media type
  195.  
  196.     AM_MEDIA_TYPE *pMediaType;
  197.     pSource->GetMediaType(&pMediaType);
  198.     pDest->SetMediaType(pMediaType);
  199.         DeleteMediaType(pMediaType);
  200.     }
  201.     {
  202.     // Copy the preroll property
  203.  
  204.     HRESULT hr = pSource->IsPreroll();
  205.     if (hr == S_OK) {
  206.         pDest->SetPreroll(TRUE);
  207.     }
  208.     else if (hr == S_FALSE) {
  209.         pDest->SetPreroll(FALSE);
  210.     }
  211.     else {    // an unexpected error has occured...
  212.         return E_UNEXPECTED;
  213.     }
  214.     }
  215.     {
  216.     // Copy the discontinuity property
  217.  
  218.     HRESULT hr = pSource->IsDiscontinuity();
  219.     if (hr == S_OK) {
  220.         pDest->SetDiscontinuity(TRUE);
  221.     }
  222.     else if (hr == S_FALSE) {
  223.         pDest->SetDiscontinuity(FALSE);
  224.     }
  225.     else {    // an unexpected error has occured...
  226.         return E_UNEXPECTED;
  227.     }
  228.     }
  229.     {
  230.         // Copy the actual data length
  231.  
  232.     long lDataLength = pSource->GetActualDataLength();
  233.         pDest->SetActualDataLength(lDataLength);
  234.     }
  235.  
  236.     return NOERROR;
  237. }
  238.  
  239.  
  240. //
  241. // Transform
  242. //
  243. // 'In place' adjust the contrast of this sample
  244. HRESULT CContrast::Transform(IMediaSample *pMediaSample) {
  245.  
  246.     signed char ContrastLevel;
  247.     {
  248.         CAutoLock l(&m_ContrastLock);
  249.  
  250.     ContrastLevel = m_ContrastLevel;    // take a copy, so we dont hold the lock
  251.                         // for the whole transform. Also ensures
  252.                         // we use the same level throughout this frame!
  253.     }
  254.  
  255.     AM_MEDIA_TYPE *pAdjustedType = NULL;
  256.  
  257.     pMediaSample->GetMediaType(&pAdjustedType);
  258.     if (pAdjustedType != NULL) {    // an upstream filter has changed the type
  259.         if (CheckInputType(&CMediaType(*pAdjustedType)) == S_OK) {    // we can handle the change
  260.  
  261.             m_pInput->CurrentMediaType() = *pAdjustedType;
  262.         CoTaskMemFree(pAdjustedType);
  263.  
  264.     }
  265.     else {
  266.         CoTaskMemFree(pAdjustedType);
  267.         return E_FAIL;
  268.     }
  269.     }
  270.  
  271.  
  272.     if (   (pAdjustedType != NULL)        // an upstream filter has changed the type
  273.         || (m_PrevLevel != ContrastLevel)    // the user has changed the type
  274.        ) {    // do transform
  275.  
  276.     CMediaType AdjustedType((AM_MEDIA_TYPE) m_pInput->CurrentMediaType());
  277.  
  278.         HRESULT hr = Transform(&AdjustedType, ContrastLevel);
  279.         if (hr == S_OK) {    // a format change was performed - inform downstream filters.
  280.             pMediaSample->SetMediaType(&AdjustedType);
  281.         m_PrevLevel = ContrastLevel;
  282.         }
  283.         else {
  284.             return hr;
  285.         }
  286.     }
  287.  
  288.     return NOERROR;
  289. }
  290.  
  291.  
  292. //
  293. // CheckInputType
  294. //
  295. // check the input type is OK.
  296. // return an error otherwise
  297. HRESULT CContrast::CheckInputType(const CMediaType *mtIn) {
  298.  
  299.     // check this is a VIDEOINFO type
  300.     if (*mtIn->FormatType() != FORMAT_VideoInfo) {
  301.         return E_INVALIDARG;
  302.     }
  303.  
  304.     if (CanChangeContrastLevel(mtIn)) {
  305.         return NOERROR;
  306.     }
  307.     else {
  308.         return E_FAIL;
  309.     }
  310. }
  311.  
  312.  
  313. //
  314. // CheckTransform
  315. //
  316. // If these types are OK as input and output (I can transform them
  317. // and they are the same) return NOERROR. Otherwise return an
  318. // error code
  319. HRESULT CContrast::CheckTransform(const CMediaType *mtIn,
  320.                                   const CMediaType *mtOut)
  321. {
  322.     if (CanChangeContrastLevel(mtIn) == TRUE) {
  323.         VIDEOINFO *pInput = (VIDEOINFO *) mtIn->Format();
  324.         VIDEOINFO *pOutput = (VIDEOINFO *) mtOut->Format();
  325.         if (memcmp(&pInput->bmiHeader,&pOutput->bmiHeader,sizeof(BITMAPINFOHEADER)) == 0) {
  326.             return NOERROR;
  327.         }
  328.     }
  329.     return E_FAIL;
  330. }
  331.  
  332.  
  333. //
  334. // DecideBufferSize
  335. //
  336. // Tell the output pin's allocator what size buffers we
  337. // require. Can only do this when the input is connected
  338. HRESULT CContrast::DecideBufferSize(IMemAllocator *pAlloc,
  339.                                     ALLOCATOR_PROPERTIES *pProperties)
  340. {
  341.     if (!m_pInput->IsConnected()) {
  342.         return E_UNEXPECTED;
  343.     }
  344.  
  345.     ASSERT(pAlloc);
  346.     ASSERT(pProperties);
  347.     HRESULT hr = NOERROR;
  348.  
  349.     pProperties->cBuffers = 1;
  350.     pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize();
  351.  
  352.     ASSERT(pProperties->cbBuffer);
  353.  
  354.     // If we don't have fixed sized samples we must guess some size
  355.  
  356.     if (!m_pInput->CurrentMediaType().bFixedSizeSamples) {
  357.         if (pProperties->cbBuffer < 100000) {
  358.             // nothing more than a guess!!
  359.             pProperties->cbBuffer = 100000;
  360.         }
  361.     }
  362.  
  363.     // Ask the allocator to reserve us some sample memory, NOTE the function
  364.     // can succeed (that is return NOERROR) but still not have allocated the
  365.     // memory that we requested, so we must check we got whatever we wanted
  366.  
  367.     ALLOCATOR_PROPERTIES Actual;
  368.     hr = pAlloc->SetProperties(pProperties,&Actual);
  369.     if (FAILED(hr)) {
  370.         return hr;
  371.     }
  372.  
  373.     ASSERT( Actual.cBuffers == 1 );
  374.  
  375.     if (pProperties->cBuffers > Actual.cBuffers ||
  376.         pProperties->cbBuffer > Actual.cbBuffer) {
  377.             return E_FAIL;
  378.     }
  379.     return NOERROR;
  380. }
  381.  
  382.  
  383. //
  384. // GetMediaType
  385. //
  386. // I support 1 type, namely the type of the input pin. This
  387. // is only available if my input is connected.
  388. HRESULT CContrast::GetMediaType(int iPosition, CMediaType *pMediaType) {
  389.  
  390.     if (m_pInput->IsConnected()) {
  391.         if (iPosition<0) {
  392.             return E_INVALIDARG;
  393.         }
  394.         if (iPosition>0) {
  395.             return VFW_S_NO_MORE_ITEMS;
  396.         }
  397.  
  398.     *pMediaType = m_pInput->CurrentMediaType();
  399.  
  400.     return NOERROR;
  401.     }
  402.     else {
  403.         return E_UNEXPECTED;
  404.     }
  405. }
  406.  
  407.  
  408.  
  409. //
  410. // --- IContrast ---
  411. //
  412.  
  413.  
  414. //
  415. // get_ContrastLevel
  416. //
  417. STDMETHODIMP CContrast::get_ContrastLevel(signed char *ContrastLevel) {
  418.  
  419.     CAutoLock l(&m_ContrastLock);
  420.  
  421.     *ContrastLevel = m_ContrastLevel;
  422.  
  423.     DbgLog((LOG_TRACE, 1, TEXT("get_ContrastLevel: %d"), *ContrastLevel));
  424.  
  425.     return NOERROR;
  426. }
  427.  
  428.  
  429. //
  430. // put_ContrastLevel
  431. //
  432. STDMETHODIMP CContrast::put_ContrastLevel(signed char ContrastLevel, unsigned long ChangeTime) {
  433.  
  434.     CAutoLock l(&m_ContrastLock);
  435.  
  436.     m_ContrastLevel = ContrastLevel;
  437.  
  438.     DbgLog((LOG_TRACE, 1, TEXT("put_ContrastLevel: %x, (time: %x)"), m_ContrastLevel, ChangeTime));
  439.  
  440.     return NOERROR;
  441. }
  442.  
  443.  
  444. //
  445. // put_DefaultContrastLevel
  446. //
  447. STDMETHODIMP CContrast::put_DefaultContrastLevel(void) {
  448.  
  449.     CAutoLock l(&m_ContrastLock);
  450.  
  451.     DbgLog((LOG_TRACE, 1, TEXT("put_DefaultContrastLevel")));
  452.  
  453.     m_ContrastLevel = m_DefaultContrastLevel;
  454.  
  455.     return NOERROR;
  456. }
  457.  
  458.  
  459. //
  460. // --- ISpecifyPropertyPages ---
  461. //
  462.  
  463.  
  464. //
  465. // GetPages
  466. //
  467. // Returns the clsid's of the property pages we support
  468. STDMETHODIMP CContrast::GetPages(CAUUID *pPages) {
  469.  
  470.     pPages->cElems = 1;
  471.     pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
  472.     if (pPages->pElems == NULL) {
  473.         return E_OUTOFMEMORY;
  474.     }
  475.     *(pPages->pElems) = CLSID_ContrastPropertyPage;
  476.  
  477.     return NOERROR;
  478. }
  479.  
  480.  
  481. //
  482. // CanChangeContrastLevel
  483. //
  484. // Check if this is a paletised format
  485. BOOL CContrast::CanChangeContrastLevel(const CMediaType *pMediaType) const {
  486.  
  487.     if (   (IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Video))
  488.         && (IsEqualGUID(*pMediaType->Subtype(), MEDIASUBTYPE_RGB8))
  489.        ) {
  490.  
  491.         // I think I can process this format (8 bit palettised)
  492.     // So do a quick sanity check on the palette info
  493.  
  494.     VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->Format();
  495.  
  496.     return (   (pvi->bmiHeader.biClrUsed > 0)    // there is a palette
  497.             && (pvi->bmiHeader.biBitCount == 8)    // media type & videoinfo agree
  498.            );
  499.     }
  500.     else {    // cant process this
  501.         return FALSE;
  502.     }
  503. }
  504.  
  505.  
  506. //
  507. // TransformMediaType
  508. //
  509. // Adjust the palette entries of pType to reflect the specified contrast level
  510. HRESULT CContrast::Transform(AM_MEDIA_TYPE *pType, const signed char ContrastLevel) const {
  511.  
  512.     VIDEOINFO *pvi = (VIDEOINFO *) pType->pbFormat;
  513.  
  514.     if (ContrastLevel >= 0) {
  515.         int Low    = 0 + m_ContrastLevel;
  516.         int High    = 255 - m_ContrastLevel;
  517.     float Grad    = ((float)(High - Low)) / 255;
  518.  
  519.         for (UINT i = 0; i < pvi->bmiHeader.biClrUsed; i++) {
  520.  
  521.             IncreaseContrast(&pvi->bmiColors[i], Low, High, Grad);
  522.         }
  523.     }
  524.     else {
  525.         float Grad = 255 / (255 + (float) ContrastLevel + (float) ContrastLevel);
  526.  
  527.         for (UINT i = 0; i < pvi->bmiHeader.biClrUsed; i++) {
  528.  
  529.             DecreaseContrast(&pvi->bmiColors[i], ContrastLevel, Grad);
  530.         }
  531.     }
  532.  
  533.     return NOERROR;
  534. }
  535.  
  536.  
  537.  
  538. //
  539. // ChangeContrast
  540. //
  541. // Adjust the contrast of this palette element
  542. inline
  543. void CContrast::IncreaseContrast(RGBQUAD *pElem, const int Low, const int High, const float Grad) const {
  544.  
  545.     IncreaseContrast(&pElem->rgbRed, Low, High, Grad);
  546.     IncreaseContrast(&pElem->rgbGreen, Low, High, Grad);
  547.     IncreaseContrast(&pElem->rgbBlue, Low, High, Grad);
  548. }
  549.  
  550.  
  551. //
  552. // ChangeContrast
  553. //
  554. // Change this byte's contrast
  555. inline
  556. void CContrast::IncreaseContrast(BYTE *pByte, const int Low, const int High, const float Grad) const {
  557.  
  558.     if (*pByte <= Low) {
  559.         *pByte = 0;
  560.     }
  561.     else if (   ( Low < *pByte )
  562.              && ( *pByte <  High )
  563.         ) {
  564.     *pByte = (BYTE)( (*pByte - Low) / Grad);
  565.     }
  566.     else {    // pElem->rgbGreen >= High
  567.         *pByte = 255;
  568.     }
  569. }
  570.  
  571.  
  572. //
  573. // DecreaseContrast
  574. //
  575. // Adjust the contrast of this palette element
  576. inline
  577. void CContrast::DecreaseContrast(RGBQUAD *pElem, const int Level, const float Grad) const {
  578.  
  579.     DecreaseContrast(&pElem->rgbRed, Level, Grad);
  580.     DecreaseContrast(&pElem->rgbGreen, Level, Grad);
  581.     DecreaseContrast(&pElem->rgbBlue, Level, Grad);
  582. }
  583.  
  584.  
  585. //
  586. // DecreaseContrast
  587. //
  588. // Use different maths to calculate the 'decreasing contrast' line
  589. inline
  590. void CContrast::DecreaseContrast(BYTE *pByte, const int Level, const float Grad) const {
  591.  
  592.     ASSERT(Grad != 0.0);
  593.  
  594.     *pByte = (BYTE) ( ((int) (*pByte / Grad)) - Level);
  595. }
  596.  
  597.  
  598. /******************************Public*Routine******************************\
  599. * exported entry points for registration and
  600. * unregistration (in this case they only call
  601. * through to default implmentations).
  602. *
  603. *
  604. *
  605. * History:
  606. *
  607. \**************************************************************************/
  608. HRESULT
  609. DllRegisterServer()
  610. {
  611.   return AMovieDllRegisterServer();
  612. }
  613.  
  614. HRESULT
  615. DllUnregisterServer()
  616. {
  617.   return AMovieDllUnregisterServer();
  618. }
  619.  
  620.