一个最简单的源Filter的编写步骤

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

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


view plain copy to clipboard print ?
//MySourceFilter.h   
class  CMySourceFilter   
    //从SDK库中的CSource类派生   
    :   public  CSource            
{  
public :  
    //实例化接口   
    static  CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk,  HRESULT  *phr);  
private :  
    //构造函数   
    CMySourceFilter(LPUNKNOWN lpunk, HRESULT  *phr);   
};  
view plain copy to clipboard print ?
//MyOutputPin.h   
class  CMyOutputPin   
    //CSource的派生类都使用 CSourceStream的派生类做为pin   
    :public  CSourceStream  
{  
public :  
    CMyOutputPin(HRESULT  *phr, CSource *pFilter);  
    ~CMyOutputPin(void );  
  
    //填充样本函数   
    //参数pMediaSample就是要传递到下一个 Filter输入pin的样本   
    //把数据填充到pMediaSample中就是这个函数的功能   
    HRESULT  FillBuffer(IMediaSample *pMediaSample);  
  
    //协商每个CMediaSample数据块的大小   
    HRESULT  DecideBufferSize(IMemAllocator *pIMemAlloc,  
        ALLOCATOR_PROPERTIES *pProperties);  
  
    //获得媒体类型   
    //在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型   
    //此函数设置pmt的各个成员,因此,由此函数的内容觉 得PIN支持什么媒体类型   
    HRESULT  GetMediaType( int  iPosition, CMediaType *pmt);  
  
    //检测是否支持参数传入的媒体类型   
    HRESULT  CheckMediaType( const  CMediaType *pMediaType);  
  
    //这是质量控制接口,最简单的源Filter不需要质量控制   
    STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)  
    {  
        return  E_FAIL;  
    }  
  
private :  
    BYTE * m_pData[3]; //存储图片数据   
    int  m_nWidth; //图片的宽   
    int  m_nHeight; //图片的高   
    int  m_nImageSize; //图片数据的大小   
    int  m_nCount; //计数器,用来切换图片数据的缓冲区   
};  
3.实现CMySourceFilter类。这个类只有两个函数需要编写,很简单。
view plain copy to clipboard print ?
//CMySourceFilter.cpp   
CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT  *phr)  
{  
    //实例化函数的工作就是实例化一个源Filter的对象   
     CUnknown *punk = new  CMySourceFilter(lpunk,phr);  
     if  (punk == NULL)  
     {  
         *phr = E_OUTOFMEMORY;  
     }  
     return  punk;  
}  
  
CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT  *phr)  
 : CSource(L"MyFilter" ,lpunk,CLSID_MyFilter,phr)  
{  
    //创建一个pin的对象实例   
    //在CSourceStream的构造函数中,会把pin 添加到Filter中   
    CMyOutputPin* pOutPin = new  CMyOutputPin(phr, this );  
    if  (FAILED(*phr))  
    {  
        //因此,在创建失败的时候,要将这个pin从Filter中移除   
        RemovePin(pOutPin);  
        pOutPin->Release();  
    }  
}  
4.实现CMyOutputPin类,编写Filter主要就是写pin。
view plain copy to clipboard print ?
//MyOutputPin.cpp   
  
//构造函数   
CMyOutputPin::CMyOutputPin(HRESULT  *phr, CSource *pFilter)  
: CSourceStream(L"MyFilter" ,phr,pFilter,L "Out" )  
, m_nWidth(0)  
, m_nHeight(0)  
, m_nImageSize(0)  
, m_nCount(0)  
{  
    //把图片读到内存中,准备好数据   
    m_pData[0] = LoadBitmapFileToMemory(L"E:\\DirectShow\\MySourceFilter\\1.bmp" ,  
        m_nWidth,m_nHeight,m_nImageSize);  
    m_pData[1] = LoadBitmapFileToMemory(L"E:\\DirectShow\\MySourceFilter\\2.bmp" ,  
        m_nWidth,m_nHeight,m_nImageSize);  
    m_pData[2] = LoadBitmapFileToMemory(L"E:\\DirectShow\\MySourceFilter\\3.bmp" ,  
        m_nWidth,m_nHeight,m_nImageSize);  
}  
  
//析构函数   
CMyOutputPin::~CMyOutputPin(void )  
{  
    //释放内存   
    delete  []m_pData[0];  
    delete  []m_pData[1];  
    delete  []m_pData[2];  
}  
  
//获取媒体类型   
//填充pmt   
//最简单的源Filter,因此只支持一种类型,所以 iPosition为0   
HRESULT  CMyOutputPin::GetMediaType( int  iPosition, CMediaType *pmt)  
{  
    CheckPointer(pmt,E_POINTER);  
  
    CAutoLock cAutoLock(m_pFilter->pStateLock());  
    if (iPosition < 0)  
    {  
        return  E_INVALIDARG;  
    }  
    // Have we run off the end of types?   
    if (iPosition > 0)  
    {  
        return  VFW_S_NO_MORE_ITEMS;  
    }  
  
    //给媒体类型申请Format的空间   
    //填充每一个对象,主要是BITMAPINFOHEADER结 构   
    VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof (VIDEOINFO));  
    if (NULL == pvi)  
        return (E_OUTOFMEMORY);  
  
    ZeroMemory(pvi, sizeof (VIDEOINFO));  
    pvi->bmiHeader.biBitCount = 24;  
    pvi->bmiHeader.biHeight = m_nHeight;  
    pvi->bmiHeader.biWidth = m_nWidth;  
    pvi->bmiHeader.biSizeImage = m_nImageSize;  
    pvi->bmiHeader.biPlanes = 1;  
    pvi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);  
    pvi->bmiHeader.biCompression = BI_RGB;  
    pvi->bmiHeader.biClrImportant = 0;  
  
    SetRectEmpty(&pvi->rcSource);  
    SetRectEmpty(&pvi->rcTarget);  
  
    pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型   
    pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型   
    pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型   
    pmt->SetSampleSize(m_nImageSize);//设置Sample的大小   
    pmt->SetTemporalCompression(FALSE);  
  
    return  NOERROR;  
}  
  
//检查媒体类型   
//主要是对GetMediaType中设置的各个参数进行比较   
HRESULT  CMyOutputPin::CheckMediaType( const  CMediaType *pMediaType)  
{  
    CheckPointer(pMediaType,E_POINTER);  
  
    if  (*(pMediaType->Type()) != MEDIATYPE_Video  
        || !(pMediaType->IsFixedSize()))  
    {  
        return  E_INVALIDARG;  
    }  
  
    const  GUID *SubType = pMediaType->Subtype();  
    if  (SubType == NULL)  
    {  
        return  E_INVALIDARG;  
    }  
    if  (*SubType != MEDIASUBTYPE_RGB24)  
    {  
        return  E_INVALIDARG;  
    }  
    const  GUID* FormatType = pMediaType->FormatType();  
    if  (FormatType == NULL)  
    {  
        return  E_INVALIDARG;  
    }  
    if  (*FormatType != FORMAT_VideoInfo)  
    {  
        return  E_INVALIDARG;  
    }  
  
    VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format();  
    if  (pvi == NULL)  
    {  
        return  E_INVALIDARG;  
    }  
    if  (pvi->bmiHeader.biBitCount != 24 ||   
        pvi->bmiHeader.biWidth != m_nWidth ||  
        pvi->bmiHeader.biHeight != m_nHeight)  
    {  
        return  E_INVALIDARG;  
    }  
  
    return  S_OK;  
}  
  
//协商Sample的大小   
HRESULT  CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties)  
{  
    CheckPointer(pIMemAlloc,E_POINTER);  
    CheckPointer(pProperties,E_POINTER);  
  
    CAutoLock cAutoLock(m_pFilter->pStateLock());  
    HRESULT  hr = NOERROR;  
  
    VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();  
    //确定只有一个buffer   
    pProperties->cBuffers = 1;  
    //设置buffer的大小   
    pProperties->cbBuffer = m_nImageSize;  
  
    ASSERT(pProperties->cbBuffer);  
  
    //设置属性页   
    ALLOCATOR_PROPERTIES Actual;  
    hr = pIMemAlloc->SetProperties(pProperties,&Actual);  
    if (FAILED(hr))  
    {  
        return  hr;  
    }  
  
    if (Actual.cbBuffer < pProperties->cbBuffer)  
    {  
        return  E_FAIL;  
    }  
  
    ASSERT(Actual.cBuffers == 1);  
    return  NOERROR;  
}  
  
//填充Sample   
HRESULT  CMyOutputPin::FillBuffer(IMediaSample *pMediaSample)  
{  
    CheckPointer(pMediaSample,E_POINTER);  
    BYTE * pData = NULL;  
    long  lDataSize = 0;  
  
    //获得Sample中存放数据的地址   
    pMediaSample->GetPointer(&pData);  
    //取得Sample分配的内存大小   
    lDataSize = pMediaSample->GetSize();  
  
    ZeroMemory(pData,lDataSize);  
    //把当前需要显示的数据拷贝到内存中   
    CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize);  
  
    //设置时间戳   
    REFERENCE_TIME start = TS_ONE * m_nCount;  
    REFERENCE_TIME stop = TS_ONE + start;  
    pMediaSample->SetTime(&start,&stop);  
  
    //准备下一帧数据   
    m_nCount++;  
  
    pMediaSample->SetSyncPoint(TRUE);      
  
    return  NOERROR;  
}  
LoadBitmapFileToMemory函数的实现
view plain copy to clipboard print ?
BYTE * LoadBitmapFileToMemory( TCHAR * pFileName,  int & nWidth,  int & nHeight,  int & nImageDataSize)  
{  
    HBITMAP  hBitmap = ( HBITMAP )LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0,  
        LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );  
  
    if (hBitmap == NULL)  
        return  NULL;  
  
    HDC  hDC = CreateCompatibleDC(NULL);  
    HBITMAP  hOldBitmap = ( HBITMAP )SelectObject(hDC, hBitmap);  
  
    BITMAP bmp;  
    GetObject(hBitmap, sizeof (bmp), &bmp);  
  
    BITMAPINFOHEADER bih = {0};//位图信息头   
    bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小   
    bih.biCompression = BI_RGB;  
    bih.biHeight = bmp.bmHeight;//高 度   
    bih.biPlanes = 1;  
    bih.biSize = sizeof (BITMAPINFOHEADER);  
    bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小   
    bih.biWidth = bmp.bmWidth;//宽度   
  
    nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight;  
    byte * p = new  byte[nImageDataSize]; //申请内存保存位图数据   
    GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p,  
        (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据   
  
    SelectObject(hDC, hOldBitmap);  
    DeleteObject(hBitmap);  
    DeleteDC(hDC);  
  
    nWidth = bmp.bmWidth;  
    nHeight = bmp.bmHeight;  
  
    return  p;  
}  
5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。
view plain copy to clipboard print ?
//MySourceFilter.h   
//动态库工程自然也要有入口函数(固定格式)   
    extern   "C"   BOOL  WINAPI DllEntryPoint( HINSTANCE ,  ULONG ,  LPVOID );  
  
    BOOL  APIENTRY DllMain( HANDLE  hModule,   
        DWORD   dwReason,   
        LPVOID  lpReserved)  
    {  
        return  DllEntryPoint(( HINSTANCE )(hModule), dwReason, lpReserved);  
    }  
//组件就少不了注册与注销函数(固定格式)   
STDAPI DllRegisterServer()  
    {  
        return  AMovieDllRegisterServer2(TRUE);  
  
    }  
STDAPI DllUnregisterServer()  
    {  
        return  AMovieDllRegisterServer2(FALSE);  
  
    }  
  
//组件,就要有GUID(通过工具创建)   
DEFINE_GUID(CLSID_MyFilter,   
            0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1);  
  
//以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认   
const  AMOVIESETUP_MEDIATYPE sudOpPinTypes =  
{  
    &MEDIATYPE_Video,       // Major type   
    &MEDIASUBTYPE_NULL      // Minor type   
};  
  
const  AMOVIESETUP_PIN sudOpPin =  
{  
    L"Output" ,               
    FALSE,                   
    TRUE,                     
    FALSE,                    
    FALSE,                    
    &CLSID_NULL,             
    NULL,                    
    1,                        
    &sudOpPinTypes };       
  
    const  AMOVIESETUP_FILTER sudBallax =  
    {  
        &CLSID_MyFilter,    // 自定义的GUID   
        L"MyFilter" ,        // Filter的名字   
        MERIT_DO_NOT_USE,         
        1,                        
        &sudOpPin           
    };  
  
  
    // COM global table of objects in this dll   
  
    CFactoryTemplate g_Templates[] = {  
        { L"MyFilter" //Filter的名字   
        , &CLSID_MyFilter//自定义的 GUID   
        , CMySourceFilter::CreateInstance//Filter的实例化接口   
        , NULL  
        , &sudBallax }  
    };  
    int  g_cTemplates =  sizeof (g_Templates) /  sizeof (g_Templates[0]);  
6.MySourceFilter.def文件的内容
view plain copy to clipboard print ?
LIBRARY  "MySourceFilter.ax"   
  
EXPORTS  
            DllMain                 PRIVATE  
            DllGetClassObject       PRIVATE  
            DllCanUnloadNow         PRIVATE  
            DllRegisterServer       PRIVATE  
            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,效果出来了,三幅图片轮流显示在窗口中。
### 回答1: 我可以为您提供一个示例代码: #include <stdio.h> #define PI 3.1415926 // 卡尔曼滤波算法 void KalmanFilter(double* X, double* P, double* K, double* Y, double R, double Q, double A, double B, double H) { *X = (*A) * (*X) + (*B) * (*Y); *P = (*A) * (*P) * (*A) + (*Q); *K = (*P) * (*H) / ((*H) * (*P) * (*H) + (*R)); *X = (*X) + (*K) * (*Y - (*H) * (*X)); *P = (*P) - (*K) * (*H) * (*P); } int main() { double X, P, K; double R = 0.1, Q = 0.001, A = 1, B = 0, H = 1; double Y; // 初始化状态 X = 0; P = 1; // 测量值 Y = 1.1; // 计算 KalmanFilter(&X, &P, &K, &Y, R, Q, A, B, H); printf("X=%f \n", X); printf("P=%f \n", P); printf("K=%f \n", K); return 0; } ### 回答2: 卡尔曼滤波是一种用于估计系统状态的线性滤波算法,广泛应用于航天、导航、机器人等领域。下面是一个C语言实现的简单卡尔曼滤波算法程序示例: ```c #include <stdio.h> #define Q 0.01 // 系统过程噪声协方差 #define R 0.1 // 测量噪声协方差 float kalman_filter(float z, float *x, float *P) { // 预测步骤 float x_hat = *x; // 状态预测值 float P_hat = *P + Q; // 状态协方差预测值 // 更新步骤 float K = P_hat / (P_hat + R); // 卡尔曼增益 *x = x_hat + K * (z - x_hat); // 更新状态估计值 *P = (1 - K) * P_hat; // 更新状态协方差估计值 return *x; } int main() { float z[] = {1.2, 2.1, 3.4, 4.3}; // 测量值 float x = 0; // 初始状态估计值 float P = 1; // 初始状态协方差估计值 int n = sizeof(z) / sizeof(float); for (int i = 0; i < n; ++i) { float filtered_value = kalman_filter(z[i], &x, &P); printf("测量值:%f ;滤波值:%f\n", z[i], filtered_value); } return 0; } ``` 这个程序中,首先定义了系统过程噪声协方差Q和测量噪声协方差R。在`kalman_filter`函数中,根据卡尔曼滤波算法的预测和更新步骤,计算状态预测值`x_hat`和状态协方差预测值`P_hat`,然后根据测量值`z`更新状态估计值`x`和状态协方差估计值`P`,最后返回状态估计值作为滤波值。在`main`函数中,我们可以定义一组测量值序列`z`,并通过循环调用`kalman_filter`函数来获得滤波值。最后,将测量值和滤波值打印出来。 ### 回答3: 卡尔曼滤波算法是一种常用于估计系统状态的方法,它可以通过利用过去的测量数据和系统动态模型来优化当前状态的估计。以下是一个简单的C语言卡尔曼滤波算法程序的示例: ```c #include <stdio.h> // 卡尔曼滤波函数 float kalmanFilter(float measurement) { // 初始化状态变量 float x_hat = 0; float P = 1; float Q = 0.01; float R = 0.1; // 预测步骤 float x_hat_minus = x_hat; float P_minus = P + Q; // 更新步骤 float K = P_minus / (P_minus + R); x_hat = x_hat_minus + K * (measurement - x_hat_minus); P = (1 - K) * P_minus; return x_hat; } int main() { // 测量数据示例 float measurement = 10.0; // 调用卡尔曼滤波函数进行状态估计 float estimated_state = kalmanFilter(measurement); // 输出估计结果 printf("Estimated State: %.2f\n", estimated_state); return 0; } ``` 该程序实现了一个简单的一维卡尔曼滤波器。在`kalmanFilter`函数中,测量值作为输入,函数返回一个估计的状态值。在主函数中,我们传递了一个测量值,并输出了估计的状态值。 需要注意的是,该示例程序的参数Q、R和初始状态值可以根据具体应用进行调整。另外,该程序仅实现了简单的一维情况,对于多维情况需要对状态变量和矩阵进行相应的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值