• DirectShow基础编程 最简单的源Filter的编写步骤 (转)


    转自: http://blog.csdn.net/bwmwm/article/details/5463852

    1.创建一个空的Dll工程,添加5个空文件分别名为:MyOutputPin.h、MySourceFilter.h、MyOutputPin.cpp、MySourceFilter.cpp和MySourceFilter.def。

    2.声明两个类,一个是Filter的实现类,一个是输出Pin的实现类,由于是最简单的源Filter,因此Filter只有一个输出Pin。实现的功能是从本地磁盘读取三个图片文件,轮流显示这三张图片,效果是模拟一个视频流。这两个类的声明代码:

    1. //MySourceFilter.h  
    2. class CMySourceFilter   
    3.     //从SDK库中的CSource类派生  
    4.     :   public CSource            
    5. {  
    6. public:  
    7.     //实例化接口  
    8.     static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);  
    9. private:  
    10.     //构造函数  
    11.     CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr);   
    12. };  
    1. //MyOutputPin.h  
    2. class CMyOutputPin   
    3.     //CSource的派生类都使用CSourceStream的派生类做为pin  
    4.     :public CSourceStream  
    5. {  
    6. public:  
    7.     CMyOutputPin(HRESULT *phr, CSource *pFilter);  
    8.     ~CMyOutputPin(void);  
    9.   
    10.     //填充样本函数  
    11.     //参数pMediaSample就是要传递到下一个Filter输入pin的样本  
    12.     //把数据填充到pMediaSample中就是这个函数的功能  
    13.     HRESULT FillBuffer(IMediaSample *pMediaSample);  
    14.   
    15.     //协商每个CMediaSample数据块的大小  
    16.     HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc,  
    17.         ALLOCATOR_PROPERTIES *pProperties);  
    18.   
    19.     //获得媒体类型  
    20.     //在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型  
    21.     //此函数设置pmt的各个成员,因此,由此函数的内容觉得PIN支持什么媒体类型  
    22.     HRESULT GetMediaType(int iPosition, CMediaType *pmt);  
    23.   
    24.     //检测是否支持参数传入的媒体类型  
    25.     HRESULT CheckMediaType(const CMediaType *pMediaType);  
    26.   
    27.     //这是质量控制接口,最简单的源Filter不需要质量控制  
    28.     STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)  
    29.     {  
    30.         return E_FAIL;  
    31.     }  
    32.   
    33. private:  
    34.     BYTE* m_pData[3];//存储图片数据  
    35.     int m_nWidth;//图片的宽  
    36.     int m_nHeight;//图片的高  
    37.     int m_nImageSize;//图片数据的大小  
    38.     int m_nCount;//计数器,用来切换图片数据的缓冲区  
    39. };  

    3.实现CMySourceFilter类。这个类只有两个函数需要编写,很简单。

    1. //CMySourceFilter.cpp  
    2. CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)  
    3. {  
    4.     //实例化函数的工作就是实例化一个源Filter的对象  
    5.      CUnknown *punk = new CMySourceFilter(lpunk,phr);  
    6.      if (punk == NULL)  
    7.      {  
    8.          *phr = E_OUTOFMEMORY;  
    9.      }  
    10.      return punk;  
    11. }  
    12.   
    13. CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr)  
    14.  : CSource(L"MyFilter",lpunk,CLSID_MyFilter,phr)  
    15. {  
    16.     //创建一个pin的对象实例  
    17.     //在CSourceStream的构造函数中,会把pin添加到Filter中  
    18.     CMyOutputPin* pOutPin = new CMyOutputPin(phr,this);  
    19.     if (FAILED(*phr))  
    20.     {  
    21.         //因此,在创建失败的时候,要将这个pin从Filter中移除  
    22.         RemovePin(pOutPin);  
    23.         pOutPin->Release();  
    24.     }  
    25. }  

    4.实现CMyOutputPin类,编写Filter主要就是写pin。

    1. //MyOutputPin.cpp  
    2.   
    3. //构造函数  
    4. CMyOutputPin::CMyOutputPin(HRESULT *phr, CSource *pFilter)  
    5. : CSourceStream(L"MyFilter",phr,pFilter,L"Out")  
    6. , m_nWidth(0)  
    7. , m_nHeight(0)  
    8. , m_nImageSize(0)  
    9. , m_nCount(0)  
    10. {  
    11.     //把图片读到内存中,准备好数据  
    12.     m_pData[0] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//1.bmp",  
    13.         m_nWidth,m_nHeight,m_nImageSize);  
    14.     m_pData[1] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//2.bmp",  
    15.         m_nWidth,m_nHeight,m_nImageSize);  
    16.     m_pData[2] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//3.bmp",  
    17.         m_nWidth,m_nHeight,m_nImageSize);  
    18. }  
    19.   
    20. //析构函数  
    21. CMyOutputPin::~CMyOutputPin(void)  
    22. {  
    23.     //释放内存  
    24.     delete []m_pData[0];  
    25.     delete []m_pData[1];  
    26.     delete []m_pData[2];  
    27. }  
    28.   
    29. //获取媒体类型  
    30. //填充pmt  
    31. //最简单的源Filter,因此只支持一种类型,所以iPosition为0  
    32. HRESULT CMyOutputPin::GetMediaType(int iPosition, CMediaType *pmt)  
    33. {  
    34.     CheckPointer(pmt,E_POINTER);  
    35.   
    36.     CAutoLock cAutoLock(m_pFilter->pStateLock());  
    37.     if(iPosition < 0)  
    38.     {  
    39.         return E_INVALIDARG;  
    40.     }  
    41.     // Have we run off the end of types?  
    42.     if(iPosition > 0)  
    43.     {  
    44.         return VFW_S_NO_MORE_ITEMS;  
    45.     }  
    46.   
    47.     //给媒体类型申请Format的空间  
    48.     //填充每一个对象,主要是BITMAPINFOHEADER结构  
    49.     VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO));  
    50.     if(NULL == pvi)  
    51.         return(E_OUTOFMEMORY);  
    52.   
    53.     ZeroMemory(pvi, sizeof(VIDEOINFO));  
    54.     pvi->bmiHeader.biBitCount = 24;  
    55.     pvi->bmiHeader.biHeight = m_nHeight;  
    56.     pvi->bmiHeader.biWidth = m_nWidth;  
    57.     pvi->bmiHeader.biSizeImage = m_nImageSize;  
    58.     pvi->bmiHeader.biPlanes = 1;  
    59.     pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
    60.     pvi->bmiHeader.biCompression = BI_RGB;  
    61.     pvi->bmiHeader.biClrImportant = 0;  
    62.   
    63.     SetRectEmpty(&pvi->rcSource);  
    64.     SetRectEmpty(&pvi->rcTarget);  
    65.   
    66.     pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型  
    67.     pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型  
    68.     pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型  
    69.     pmt->SetSampleSize(m_nImageSize);//设置Sample的大小  
    70.     pmt->SetTemporalCompression(FALSE);  
    71.   
    72.     return NOERROR;  
    73. }  
    74.   
    75. //检查媒体类型  
    76. //主要是对GetMediaType中设置的各个参数进行比较  
    77. HRESULT CMyOutputPin::CheckMediaType(const CMediaType *pMediaType)  
    78. {  
    79.     CheckPointer(pMediaType,E_POINTER);  
    80.   
    81.     if (*(pMediaType->Type()) != MEDIATYPE_Video  
    82.         || !(pMediaType->IsFixedSize()))  
    83.     {  
    84.         return E_INVALIDARG;  
    85.     }  
    86.   
    87.     const GUID *SubType = pMediaType->Subtype();  
    88.     if (SubType == NULL)  
    89.     {  
    90.         return E_INVALIDARG;  
    91.     }  
    92.     if (*SubType != MEDIASUBTYPE_RGB24)  
    93.     {  
    94.         return E_INVALIDARG;  
    95.     }  
    96.     const GUID* FormatType = pMediaType->FormatType();  
    97.     if (FormatType == NULL)  
    98.     {  
    99.         return E_INVALIDARG;  
    100.     }  
    101.     if (*FormatType != FORMAT_VideoInfo)  
    102.     {  
    103.         return E_INVALIDARG;  
    104.     }  
    105.   
    106.     VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format();  
    107.     if (pvi == NULL)  
    108.     {  
    109.         return E_INVALIDARG;  
    110.     }  
    111.     if (pvi->bmiHeader.biBitCount != 24 ||   
    112.         pvi->bmiHeader.biWidth != m_nWidth ||  
    113.         pvi->bmiHeader.biHeight != m_nHeight)  
    114.     {  
    115.         return E_INVALIDARG;  
    116.     }  
    117.   
    118.     return S_OK;  
    119. }  
    120.   
    121. //协商Sample的大小  
    122. HRESULT CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties)  
    123. {  
    124.     CheckPointer(pIMemAlloc,E_POINTER);  
    125.     CheckPointer(pProperties,E_POINTER);  
    126.   
    127.     CAutoLock cAutoLock(m_pFilter->pStateLock());  
    128.     HRESULT hr = NOERROR;  
    129.   
    130.     VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();  
    131.     //确定只有一个buffer  
    132.     pProperties->cBuffers = 1;  
    133.     //设置buffer的大小  
    134.     pProperties->cbBuffer = m_nImageSize;  
    135.   
    136.     ASSERT(pProperties->cbBuffer);  
    137.   
    138.     //设置属性页  
    139.     ALLOCATOR_PROPERTIES Actual;  
    140.     hr = pIMemAlloc->SetProperties(pProperties,&Actual);  
    141.     if(FAILED(hr))  
    142.     {  
    143.         return hr;  
    144.     }  
    145.   
    146.     if(Actual.cbBuffer < pProperties->cbBuffer)  
    147.     {  
    148.         return E_FAIL;  
    149.     }  
    150.   
    151.     ASSERT(Actual.cBuffers == 1);  
    152.     return NOERROR;  
    153. }  
    154.   
    155. //填充Sample  
    156. HRESULT CMyOutputPin::FillBuffer(IMediaSample *pMediaSample)  
    157. {  
    158.     CheckPointer(pMediaSample,E_POINTER);  
    159.     BYTE* pData = NULL;  
    160.     long lDataSize = 0;  
    161.   
    162.     //获得Sample中存放数据的地址  
    163.     pMediaSample->GetPointer(&pData);  
    164.     //取得Sample分配的内存大小  
    165.     lDataSize = pMediaSample->GetSize();  
    166.   
    167.     ZeroMemory(pData,lDataSize);  
    168.     //把当前需要显示的数据拷贝到内存中  
    169.     CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize);  
    170.   
    171.     //设置时间戳  
    172.     REFERENCE_TIME start = TS_ONE * m_nCount;  
    173.     REFERENCE_TIME stop = TS_ONE + start;  
    174.     pMediaSample->SetTime(&start,&stop);  
    175.   
    176.     //准备下一帧数据  
    177.     m_nCount++;  
    178.   
    179.     pMediaSample->SetSyncPoint(TRUE);      
    180.   
    181.     return NOERROR;  
    182. }  

    LoadBitmapFileToMemory函数的实现

    1. BYTE* LoadBitmapFileToMemory(TCHAR* pFileName, int& nWidth, int& nHeight, int& nImageDataSize)  
    2. {  
    3.     HBITMAP hBitmap = (HBITMAP)LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0,  
    4.         LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );  
    5.   
    6.     if(hBitmap == NULL)  
    7.         return NULL;  
    8.   
    9.     HDC hDC = CreateCompatibleDC(NULL);  
    10.     HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap);  
    11.   
    12.     BITMAP bmp;  
    13.     GetObject(hBitmap, sizeof(bmp), &bmp);  
    14.   
    15.     BITMAPINFOHEADER bih = {0};//位图信息头  
    16.     bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小  
    17.     bih.biCompression = BI_RGB;  
    18.     bih.biHeight = bmp.bmHeight;//高度  
    19.     bih.biPlanes = 1;  
    20.     bih.biSize = sizeof(BITMAPINFOHEADER);  
    21.     bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小  
    22.     bih.biWidth = bmp.bmWidth;//宽度  
    23.   
    24.     nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight;  
    25.     byte * p = new byte[nImageDataSize];//申请内存保存位图数据  
    26.     GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p,  
    27.         (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据  
    28.   
    29.     SelectObject(hDC, hOldBitmap);  
    30.     DeleteObject(hBitmap);  
    31.     DeleteDC(hDC);  
    32.   
    33.     nWidth = bmp.bmWidth;  
    34.     nHeight = bmp.bmHeight;  
    35.   
    36.     return p;  
    37. }  

    5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。

    1. //MySourceFilter.h  
    2. //动态库工程自然也要有入口函数(固定格式)  
    3.     extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);  
    4.   
    5.     BOOL APIENTRY DllMain(HANDLE hModule,   
    6.         DWORD  dwReason,   
    7.         LPVOID lpReserved)  
    8.     {  
    9.         return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);  
    10.     }  
    11. //组件就少不了注册与注销函数(固定格式)  
    12. STDAPI DllRegisterServer()  
    13.     {  
    14.         return AMovieDllRegisterServer2(TRUE);  
    15.   
    16.     }  
    17. STDAPI DllUnregisterServer()  
    18.     {  
    19.         return AMovieDllRegisterServer2(FALSE);  
    20.   
    21.     }  
    22.   
    23. //组件,就要有GUID(通过工具创建)  
    24. DEFINE_GUID(CLSID_MyFilter,   
    25.             0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1);  
    26.   
    27. //以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认  
    28. const AMOVIESETUP_MEDIATYPE sudOpPinTypes =  
    29. {  
    30.     &MEDIATYPE_Video,       // Major type  
    31.     &MEDIASUBTYPE_NULL      // Minor type  
    32. };  
    33.   
    34. const AMOVIESETUP_PIN sudOpPin =  
    35. {  
    36.     L"Output",               
    37.     FALSE,                   
    38.     TRUE,                     
    39.     FALSE,                    
    40.     FALSE,                    
    41.     &CLSID_NULL,             
    42.     NULL,                    
    43.     1,                        
    44.     &sudOpPinTypes };       
    45.   
    46.     const AMOVIESETUP_FILTER sudBallax =  
    47.     {  
    48.         &CLSID_MyFilter,    // 自定义的GUID  
    49.         L"MyFilter",       // Filter的名字  
    50.         MERIT_DO_NOT_USE,         
    51.         1,                        
    52.         &sudOpPin           
    53.     };  
    54.   
    55.   
    56.     // COM global table of objects in this dll  
    57.   
    58.     CFactoryTemplate g_Templates[] = {  
    59.         { L"MyFilter"//Filter的名字  
    60.         , &CLSID_MyFilter//自定义的GUID  
    61.         , CMySourceFilter::CreateInstance//Filter的实例化接口  
    62.         , NULL  
    63.         , &sudBallax }  
    64.     };  
    65.     int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);  

    6.MySourceFilter.def文件的内容

    1. LIBRARY "MySourceFilter.ax"  
    2.   
    3. EXPORTS  
    4.             DllMain                 PRIVATE  
    5.             DllGetClassObject       PRIVATE  
    6.             DllCanUnloadNow         PRIVATE  
    7.             DllRegisterServer       PRIVATE  
    8.             DllUnregisterServer     PRIVATE  

    7.注意

    1)包含头文件 #include <initguid.h>,否则有可能提示 error LNK2001: 无法解析的外部符号 _CLSID_MyFilter

    2)包含导出库#pragma comment(lib, "winmm")

    3)包含导入库#pragma comment(lib, "strmbase.lib"),Debug下包含#pragma comment(lib, "strmbasd.lib")

    8.大功告成。调用regsvr32注册Filter。使用GraphEdit调试Filter。(VS2005)

    在工程的属性中选择调试,在命令中填入GraphEdit的完整路径,把Filter的工程作为启动项。按下F5,在运行的GraphEdit中选择我们的Filter,Render pin,就可以看到一条完整的链路,然后run,效果出来了,三幅图片轮流显示在窗口中。

  • 相关阅读:
    Kafka 再均衡监听器示例
    Spring boot中异步线程池
    【Java&Go并发编程系列】4.等待一组并发任务完成——CountDownLatch VS sync.WaitGroup
    Redis常用命令对应到Redisson对象操作
    js清空缓存,ajax
    phpexcel用法 转、
    composer 使用
    转:git操作
    手机微信内支付
    微信扫码支付
  • 原文地址:https://www.cnblogs.com/signal/p/4094102.html
Copyright © 2020-2023  润新知