织梦CMS - 轻松建站从此开始!

罗索

做了一个directshow的filter,把RGB视频流变成黑白的

jackyhwei 发布于 2011-09-26 23:19 点击:次 
这只是一个示例的程序而已,里面有好多东西,其实将来写从CTransformFilter继承的 transform filter是完全可以重复使用的,也就是里面的很多东西都差不多都会是这样。代码简单,真正自己的实现只是一个函数而已,里面只是得到像素的值,然后进行转换。也就是说,transfo
TAG:

做的这个directshow的filter属于transform filter。在其间,参考了,directshow的帮助文档,一本外文的介绍directshow的书(这本书不错,里面的代码,虽然感觉有copy directshow帮助文档的成分,但是,讲的挺不错),还有vc知识库中的两篇文章了,这两篇文章也写得挺好的。如果当初我没有看,我想会走不少弯 路。

要写directshow的transform filter 已经准备了好久了。曾经用过directshow,不过里面的也就是用现成的filter组成一个filter graph,然后run,就可以了。把自己写filter看作挺难的事情。现在发现,其实写transform filter不难,当然,也只是像我这样简单的。但是,处理的速度确实是问题。

首先,directshow filter是符合com组件规范的,也就是,其是一个com组件,要符合com的规范,需要实现一些函数的,不过,已经有不少的基类了,只需要继承就可 以了,这样,对com组件所涉及的知识就少了很多。在编写directshow filter时,只要找准了要继承的基类,然后,实现里面的虚函数等等,写上自己的控制代码,就可以了。
下面先简单的给出一些源代码和说明,具体的解释,以后会做。

这个简单的transform filter由三个文件组成:

1。ToGrayFilter.def:由于filter是个基于dll的com组件,所以一般的filter要实现几个入口函数。要导出dll中 的函数有两种方法:一种是在定义函数时使用导出关键字__declspec(dllexport),也就是在.h文件中定义函数如下:

extern “C“  __declspec(dllexport)  BOOL   DllRegisterServer;等等;第二种方法是使用模块定义文件,这也是我在这里用的方法。

//ToGrayFilter.def

LIBRARY ToGrayFilter.ax

EXPORTS
   DllMain             PRIVATE    //dll的入口函数,directshow中实现的是dllEntryPoint
   DllGetClassObject    PRIVATE //用于获得类工厂指针
   DllCanUnloadNow       PRIVATE //系统空闲时会调用这个函数,确定是否可以卸载DLL
   DllRegisterServer     PRIVATE //将com组件注册到注册表中
   DllUnregisterServer    PRIVATE  //删除注册表中的com组件的注册信息

上面的函数是作为一个典型的自注册com组件dll所必需的5个导出函数。

2。ToGrayFilter.h

在这个文件中声明了一个c++类,这个类是从directshow中的一个用于方便用户编写filter的基类中继承的。

//ToGrayFilter.h
//
#ifndef TOGRAYFILTER_H_
#define TOGRAYFILTER_H_

//
// {5F2265B1-A841-4eb7-871F-5556436042AC}
DEFINE_GUID(CLSID_ToGrayFilter,
0x5f2265b1, 0xa841, 0x4eb7, 0x87, 0x1f, 0x55, 0x56, 0x43, 0x60, 0x42, 0xac);


class CToGrayFilter:public CTransformFilter
{
public: 
 CToGrayFilter(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr);  //constructor
 ~CToGrayFilter();  //destructor

public:
    // Static object-creation method (for the class factory) //必须有的
 //
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);

public:
 //implement the base filter 's method,下面5个函数是CTranseformFilter的虚函数,必须实现了的
 //
 HRESULT CheckInputType(const CMediaType *pmtIn);
 HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
 HRESULT CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut);
 HRESULT DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProp);
 HRESULT Transform(IMediaSample *pSource,IMediaSample *pDest);

 //this method is also in the base filter class,but in the base class it does noting,
 //implement here just want to get  m_VihIn and m_VihOut
 //
 HRESULT SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt);


private:
 //my own process method,这是我自己的处理函数:),在Transform这个函数中调用的
 //
 HRESULT ToGray(BYTE *pbInput,BYTE *pbOutput);
 
 //a help method ,just copy from helper document,这个函数,最终没有在这个filter中用,因为不知道为何,
 //感觉有些问题,按理说是不应该这样的。最后是自己直接操作了
 void GetVideoInfoParameters(
    const VIDEOINFOHEADER *pvih, // Pointer to the format header.
    BYTE  * const pbData,   // Pointer to the first address in the buffer.
    bool bYuv,      // Is this a YUV format? (true = YUV, false = RGB)
    DWORD *pdwWidth,        // Returns the width in pixels.
    DWORD *pdwHeight,       // Returns the height in pixels.
    LONG  *plStrideInBytes, // Add this to a row to get the new row down.
    BYTE **ppbTop          // Returns a pointer to the first byte in the
                            // top row of pixels.
     );

 VIDEOINFOHEADER m_VihIn;   // Holds the current video format (input),可以把每一帧图像当作bmp位图
    VIDEOINFOHEADER m_VihOut;  // Holds the current video format (output)

 //the imformation about every picture,put here just for speed
 //
 DWORD m_bytePerLine;//the real numbers of bits in one line,just for handy
 int m_Width;//the width of the bitmap,to use it ,just handy
 int m_Height;//the height of the bitmap
};
#endif


3。ToGrayFilter.cpp

  1. // ToGrayFilter.cpp : 定义 DLL 应用程序的入口点。 
  2. #include "stdafx.h" 
  3.  
  4. //the include file for directshow filter 
  5. #include "streams.h" //用到了filter的基类,就要包含这个头文件的 
  6. #include <initguid.h>  // 
  7. #include <tchar.h> 
  8. #include <stdio.h> 
  9.  
  10. #include "ToGrayFilter.h" 
  11.  
  12. #pragma warning(disable:4715) 
  13.  
  14. //-------------------------------------------------------------------- 
  15.  
  16. CToGrayFilter:: CToGrayFilter(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr): 
  17.     CTransformFilter(pName, pUnk, CLSID_ToGrayFilter) 
  18. {  
  19.  
  20. CToGrayFilter::~CToGrayFilter() 
  21.  
  22. //------------------------------------------
  23. //this method check this filter's input pin could receive which kind of media type 
  24. // 
  25. HRESULT CToGrayFilter::CheckInputType(const CMediaType *pmtIn) 
  26.  if ((pmtIn->majortype != MEDIATYPE_Video) || 
  27.         (pmtIn->subtype != MEDIASUBTYPE_RGB24) || 
  28.         (pmtIn->formattype != FORMAT_VideoInfo) || 
  29.         (pmtIn->cbFormat < sizeof(VIDEOINFOHEADER))) 
  30.     { 
  31.         return VFW_E_TYPE_NOT_ACCEPTED; 
  32.     } 
  33.  
  34.  VIDEOINFOHEADER *pVih = 
  35.         reinterpret_cast<VIDEOINFOHEADER*>(pmtIn->pbFormat); 
  36.  
  37.  
  38.     // Everything is good. 
  39.     return S_OK; 
  40.  
  41.  
  42. //the downstream filter check this filter's output pin ,then the method will be used 
  43. //now because the media type has not been changed ,so only return the media type of 
  44. //this filter's input pin 
  45. // 
  46. HRESULT CToGrayFilter::GetMediaType(int iPosition, CMediaType *pMediaType) 
  47.     // The output pin calls this method only if the input pin is connected. 
  48.     ASSERT(m_pInput->IsConnected()); 
  49.  
  50.     // There is only one output type that we want, which is the input type. 
  51.     if (iPosition < 0) 
  52.     { 
  53.         return E_INVALIDARG; 
  54.     } 
  55.     else if (iPosition == 0) 
  56.     { 
  57.   //this maybe OK now 
  58.         return m_pInput->ConnectionMediaType(pMediaType); 
  59.     } 
  60.     return VFW_S_NO_MORE_ITEMS; 
  61.  
  62.  
  63.  
  64. //this method checks if a proposed output type is compatible with the current input type. 
  65. //The method is also called if the input pin reconnects after the output pin connects. 
  66. // 
  67. HRESULT CToGrayFilter::CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut) 
  68.  // Check the major type. 
  69.  // 
  70.     if (mtOut->majortype != MEDIATYPE_Video) 
  71.     { 
  72.         return VFW_E_TYPE_NOT_ACCEPTED; 
  73.     } 
  74.  
  75.     // Check the subtype and format type. 
  76.  // 
  77.  
  78.  // Make sure the subtypes match 
  79.  // 
  80.     if (mtIn->subtype != mtOut->subtype) 
  81.     { 
  82.         return VFW_E_TYPE_NOT_ACCEPTED; 
  83.     } 
  84.  if ((mtOut->formattype != FORMAT_VideoInfo) || 
  85.         (mtOut->cbFormat < sizeof(VIDEOINFOHEADER))) 
  86.     { 
  87.         return VFW_E_TYPE_NOT_ACCEPTED; 
  88.     } 
  89.  
  90.  // Compare the bitmap information against the input type. 
  91.  // 
  92.     ASSERT(mtIn->formattype == FORMAT_VideoInfo); 
  93.     BITMAPINFOHEADER *pBmiOut = HEADER(mtOut->pbFormat); 
  94.     BITMAPINFOHEADER *pBmiIn = HEADER(mtIn->pbFormat); 
  95.  
  96.  if ((pBmiOut->biWidth <= pBmiIn->biWidth) && 
  97.         (pBmiOut->biHeight == abs(pBmiIn->biHeight))) 
  98.     { 
  99.        return S_OK; 
  100.     } 
  101.     return VFW_E_TYPE_NOT_ACCEPTED; 
  102.  
  103.  
  104.  
  105. //this method is used during the output pin connection process. 
  106. //the output pin is responsible for negotiating the allocation of data stream buffers 
  107. //during the pin connection process, 
  108. //even if this allocation is actually done by the input pin of the downstream filter. 
  109. // 
  110. HRESULT CToGrayFilter::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProp) 
  111.  // Make sure the input pin is connected. 
  112.  // 
  113.     if (!m_pInput->IsConnected()) 
  114.     { 
  115.         return E_UNEXPECTED; 
  116.     } 
  117.  
  118.  // Our strategy here is to use the upstream allocator as the guideline, 
  119.     // but also defer to the downstream filter's request 
  120.     // when it's compatible with us. 
  121.  
  122.  // First, find the upstream allocator... 
  123.     ALLOCATOR_PROPERTIES InputProps; 
  124.  
  125.     IMemAllocator *pAllocInput = 0; 
  126.     HRESULT hr = m_pInput->GetAllocator(&pAllocInput); 
  127.  
  128.     if (FAILED(hr)) 
  129.     { 
  130.         return hr; 
  131.     } 
  132.  
  133.  // ...now get the properties. 
  134.     hr = pAllocInput->GetProperties(&InputProps); 
  135.     pAllocInput->Release(); 
  136.  
  137.     if (FAILED(hr)) 
  138.     { 
  139.         return hr; 
  140.     } 
  141.  
  142.  // Buffer alignment should be non-zero [zero alignment makes no sense!]. 
  143.     if (pProp->cbAlign == 0) 
  144.     { 
  145.         pProp->cbAlign = 1; 
  146.     } 
  147.  
  148.     // Number of buffers must be non-zero. 
  149.     if (pProp->cbBuffer == 0) 
  150.     { 
  151.         pProp->cBuffers = 1; 
  152.     } 
  153.  
  154.  // For buffer size, find the maximum of the upstream size and 
  155.     // the downstream filter's request. 
  156.     pProp->cbBuffer = max(InputProps.cbBuffer, pProp->cbBuffer); 
  157.  
  158.     // Now set the properties on the allocator that was given to us. 
  159.     ALLOCATOR_PROPERTIES Actual; 
  160.     hr = pAlloc->SetProperties(pProp, &Actual); 
  161.     if (FAILED(hr)) 
  162.     { 
  163.         return hr; 
  164.     } 
  165.  
  166.  
  167. HRESULT CToGrayFilter::Transform(IMediaSample *pSource,IMediaSample *pDest) 
  168.  // Get pointers to the underlying buffers. 
  169.  // 
  170.     BYTE *pBufferIn, *pBufferOut; 
  171.  HRESULT hr; 
  172.     hr = pSource->GetPointer(&pBufferIn); 
  173.     if (FAILED(hr)) 
  174.     { 
  175.         return hr; 
  176.     } 
  177.     hr = pDest->GetPointer(&pBufferOut); 
  178.     if (FAILED(hr)) 
  179.     { 
  180.         return hr; 
  181.     } 
  182.  
  183.  // Process the data. 
  184.  // 
  185.  ToGray(pBufferIn,pBufferOut); 
  186.  
  187.  
  188. //------------------------------------------------------- 
  189. //this method is also in the base filter class,but in the base class
  190. // it does noting, 
  191. //implement here just want to get  m_VihIn and m_VihOut 
  192. // 
  193.  
  194. HRESULT CToGrayFilter::SetMediaType(PIN_DIRECTION direction, 
  195.                                const CMediaType *pmt) 
  196.     if (direction == PINDIR_INPUT) 
  197.     { 
  198.         ASSERT(pmt->formattype == FORMAT_VideoInfo); 
  199.         VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmt->pbFormat; 
  200.  
  201.         // WARNING! In general you cannot just copy a VIDEOINFOHEADER 
  202.         // struct, because the BITMAPINFOHEADER member may be followed by 
  203.         // random amounts of palette entries or color masks. (See VIDEOINFO 
  204.         // structure in the DShow SDK docs.) Here it's OK because we just 
  205.         // want the information that's in the VIDEOINFOHEADER struct itself. 
  206.  
  207.         CopyMemory(&m_VihIn, pVih, sizeof(VIDEOINFOHEADER)); 
  208.  
  209.     } 
  210.     else   // Output pin 
  211.     { 
  212.         ASSERT(direction == PINDIR_OUTPUT); 
  213.         ASSERT(pmt->formattype == FORMAT_VideoInfo); 
  214.         VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmt->pbFormat; 
  215.  
  216.         CopyMemory(&m_VihOut, pVih, sizeof(VIDEOINFOHEADER)); 
  217.     } 
  218.  
  219.  //------------------------------------------------ 
  220.  // 
  221.  //   DWORD m_bytePerLine;//the real numbers of bits in one line,just for handy 
  222.  //int m_Width;//the width of the bitmap,to use it ,just handy 
  223.  //int m_Height;//the height of the bitmap 
  224.  m_Width=m_VihIn.bmiHeader.biWidth; 
  225.  m_Height=m_VihIn.bmiHeader.biHeight; 
  226.  m_bytePerLine=(24*m_Width+31)/32*4; 
  227.  
  228.  
  229.     return S_OK; 
  230.  
  231. //-------------------------------------------------------------- 
  232. //my own process method ,to change the data to gray 
  233. // 
  234. HRESULT CToGrayFilter::ToGray(BYTE *pbInput,BYTE *pbOutput) 
  235.  DWORD dwWidth, dwHeight;       // Width and height in pixels (input) 
  236.     DWORD dwWidthOut, dwHeightOut; // Width and height in pixels (output) 
  237.     LONG  lStrideIn, lStrideOut;   // Stride in bytes 
  238.     BYTE  *pbSource, *pbTarget;    // First byte first row, source & target 
  239.  
  240.     
  241. //下面这一段都没有用了,因为感觉这个函数比较古怪,最后是用自己的处理bmp位图的方法得到数据的 
  242.  
  243. //GetVideoInfoParameters(&m_VihIn, pbInput,false, &dwWidth, &dwHeight,  
  244.  //      &lStrideIn, &pbSource); 
  245.   // GetVideoInfoParameters(&m_VihOut, pbOutput,false, &dwWidthOut, &dwHeightOut,  
  246.  //      &lStrideOut, &pbTarget); 
  247.  
  248.  // Formats should match (except maybe stride). 
  249.    // ASSERT(dwWidth == dwWidthOut); 
  250.     //ASSERT(abs(dwHeight) == abs(dwHeightOut)); 
  251.  
  252.  //here to process the data 
  253.  // 
  254.  /*for (DWORD y = 0; y < dwHeight; y++) 
  255.     { 
  256.         WORD *pwTarget = (WORD*)pbTarget; 
  257.         WORD *pwSource = (WORD*)pbSource; 
  258.  
  259. //下面是对RGB32的处理,所以,对于RGB24如果这样做,会有问题的 
  260.  
  261.   //RGBQUAD *pPixelTarget = (RGBQUAD*)pbTarget; 
  262.   //RGBQUAD *pPixelSource = (RGBQUAD*)pbSource; 
  263.   //      for (DWORD x = 0; x < dwWidth; x++) 
  264.   //      { 
  265.   // BYTE grayColor; 
  266.   // grayColor= 
  267.   //  (pPixelSource[x].rgbBlue+pPixelSource[x].rgbGreen+pPixelSource[x].rgbRed)/3; 
  268.   //          // pPixelTarget[x] is the x'th pixel in the row. 
  269.   //          pPixelTarget[x].rgbBlue = pPixelSource[x].rgbBlue; 
  270.   //          pPixelTarget[x].rgbGreen = pPixelSource[x].rgbGreen; 
  271.   //          pPixelTarget[x].rgbRed = pPixelSource[x].rgbRed; 
  272.   //          pPixelTarget[x].rgbReserved = 0; 
  273.   //      } 
  274.    
  275.    
  276.     }*/ 
  277.  
  278.  //want to get the imformation for myself 
  279.  // 
  280.  
  281. //也可以在这里,当每一帧图像来了的时候,都重新计算偏移等等,但是没有必要了,而且会影响速度 
  282.  //DWORD m_bytePerLine;//the real numbers of bits in one line,just for handy 
  283.  //int m_Width;//the width of the bitmap,to use it ,just handy 
  284.  //int m_Height;//the height of the bitmap 
  285.  //m_Width=m_VihIn.bmiHeader.biWidth; 
  286.  //m_Height=m_VihIn.bmiHeader.biHeight; 
  287.  //m_bytePerLine=(24*m_Width+31)/32*4; 
  288.  
  289.  BYTE rColor,gColor,bColor,changeColor; 
  290.  for (int i=0;i<m_Height;i++) 
  291.  { 
  292.   for (int j=0;j<m_Width;j++) 
  293.   { 
  294.    rColor=*(pbInput+(m_Height-i-1)*m_bytePerLine+j*3); 
  295.    gColor=*(pbInput+(m_Height-i-1)*m_bytePerLine+j*3+1); 
  296.    bColor=*(pbInput+(m_Height-i-1)*m_bytePerLine+j*3+2); 
  297.  
  298.    changeColor=(rColor+gColor+bColor)/3; 
  299.  
  300.    *(pbOutput+(m_Height-i-1)*m_bytePerLine+j*3)=changeColor; 
  301.    *(pbOutput+(m_Height-i-1)*m_bytePerLine+j*3+1)=changeColor; 
  302.    *(pbOutput+(m_Height-i-1)*m_bytePerLine+j*3+2)=changeColor; 
  303.   } 
  304.  } 
  305.  
  306.  return S_OK; 
  307.  
  308.  
  309. //下面这个函数,是从帮助文档中copy的函数,不过感觉没有什么用,实际上
  310. //在我写的这个filter中也没有用上
  311. //a helper function ,not write by me,just copy from the help docoment 
  312. // 
  313. void CToGrayFilter::GetVideoInfoParameters( 
  314.     const VIDEOINFOHEADER *pvih, // Pointer to the format header. 
  315.     BYTE  * const pbData,   // Pointer to the first address in the buffer. 
  316.     bool bYuv,      // Is this a YUV format? (true = YUV, false = RGB) 
  317.     DWORD *pdwWidth,        // Returns the width in pixels. 
  318.     DWORD *pdwHeight,       // Returns the height in pixels. 
  319.     LONG  *plStrideInBytes, // Add this to a row to get the new row down. 
  320.     BYTE **ppbTop          // Returns a pointer to the first byte in the 
  321.                             // top row of pixels. 
  322.     ) 
  323.     LONG lStride; 
  324.  
  325.     //  For 'normal' formats, biWidth is in pixels. 
  326.     //  Expand to bytes and round up to a multiple of 4. 
  327.     if ((pvih->bmiHeader.biBitCount != 0) && 
  328.         (0 == (7 & pvih->bmiHeader.biBitCount))) 
  329.     { 
  330.         lStride = (pvih->bmiHeader.biWidth * (pvih->bmiHeader.biBitCount / 8) + 3) & ~3; 
  331.     } 
  332.     else   // Otherwise, biWidth is in bytes. 
  333.     { 
  334.         lStride = pvih->bmiHeader.biWidth; 
  335.     } 
  336.  
  337.     //  If rcTarget is empty, use the whole image. 
  338.     if (IsRectEmpty(&pvih->rcTarget)) 
  339.     { 
  340.         *pdwWidth = (DWORD)pvih->bmiHeader.biWidth; 
  341.         *pdwHeight = (DWORD)(abs(pvih->bmiHeader.biHeight)); 
  342.         
  343.         if (pvih->bmiHeader.biHeight < 0 || bYuv)   // Top-down bitmap. 
  344.         { 
  345.             *plStrideInBytes = lStride; // Stride goes "down". 
  346.             *ppbTop           = pbData; // Top row is first. 
  347.         } 
  348.         else        // Bottom-up bitmap. 
  349.         { 
  350.             *plStrideInBytes = -lStride;    // Stride goes "up". 
  351.             // Bottom row is first. 
  352.             *ppbTop = pbData + lStride * (*pdwHeight - 1);  
  353.         } 
  354.     } 
  355.     else   // rcTarget is NOT empty. Use a sub-rectangle in the image. 
  356.     { 
  357.         *pdwWidth = (DWORD)(pvih->rcTarget.right - pvih->rcTarget.left); 
  358.         *pdwHeight = (DWORD)(pvih->rcTarget.bottom - pvih->rcTarget.top); 
  359.         
  360.         if (pvih->bmiHeader.biHeight < 0 || bYuv)   // Top-down bitmap. 
  361.         { 
  362.             // Same stride as above, but first pixel is modified down 
  363.             // and over by the target rectangle. 
  364.             *plStrideInBytes = lStride;     
  365.             *ppbTop = pbData + 
  366.                      lStride * pvih->rcTarget.top + 
  367.                      (pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8; 
  368.         } 
  369.         else  // Bottom-up bitmap. 
  370.         { 
  371.             *plStrideInBytes = -lStride; 
  372.             *ppbTop = pbData + 
  373.                      lStride * (pvih->bmiHeader.biHeight - pvih->rcTarget.top - 1) + 
  374.                      (pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8; 
  375.         } 
  376.     } 
  377.  
  378.   
  379.  
  380. //--------------------------------------------------- 
  381. // 
  382. CUnknown* WINAPI CToGrayFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr) 
  383. {  
  384.     CToGrayFilter *pFilter = new CToGrayFilter(NAME("To Gray Filter"), pUnk, pHr); 
  385.     if (pFilter== NULL) 
  386.     { 
  387.         *pHr = E_OUTOFMEMORY; 
  388.     } 
  389.     return pFilter; 
  390.  
  391.  
  392. //the following three method maybe the same for most of the filters 
  393. // 
  394.  
  395. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE ,DWORD,LPVOID ); 
  396.  
  397. BOOL APIENTRY DllMain(HANDLE hModule,DWORD dwRes,LPVOID pv) 
  398.  return DllEntryPoint((HINSTANCE)hModule,dwRes,pv); 
  399.  
  400. HRESULT WINAPI DllRegisterServer() 
  401.  return AMovieDllRegisterServer2(TRUE); 
  402. HRESULT WINAPI DllUnregisterServer() 
  403.  return AMovieDllRegisterServer2(FALSE); 
  404.  
  405. //--------------------------------------------------- 
  406. // 
  407. AMOVIESETUP_FILTER FilterInfo = 
  408.     &CLSID_ToGrayFilter,     // CLSID 
  409.     L"To Gray Filter",          // Name 
  410.     MERIT_DO_NOT_USE,   // Merit 
  411.     0,                  // Number of AMOVIESETUP_PIN structs 
  412.     NULL                // Pin registration information 
  413. }; 
  414.  
  415.  
  416. CFactoryTemplate g_Templates[]={  
  417.     { 
  418.   L"To Gray Filter"
  419.      &CLSID_ToGrayFilter, 
  420.      CToGrayFilter::CreateInstance, 
  421.      0, 
  422.      &FilterInfo, 
  423.  } 
  424.  
  425. }; 
  426. int g_cTemplates=sizeof(g_Templates)/sizeof(g_Templates[0]); 

上面就是我的程序的所有源代码。这只是一个示例的程序而已,里面有好多东西,其实将来写从CTransformFilter继承的 transform filter是完全可以重复使用的,也就是里面的很多东西都差不多都会是这样。代码简单,真正自己的实现只是一个函数而已,里面只是得到像素的值,然后进 行转换。也就是说,transformfilter有一个架子,不同的只是对像素的操作而已。

现在匆匆收场了,其实还有好多没有提到的地方,但是现在心情突然不好了,以后再补充吧。

文章:来源

(mengaim_cn)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201109/15051.html]
本文出处:blog.csdn.net/mengaim_cn 作者:mengaim_cn
顶一下
(5)
83.3%
踩一下
(1)
16.7%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容