65.9K
CodeProject 正在变化。 阅读更多。
Home

为 Windows Mobile 创建自定义 DirectShow SampleGrabber 过滤器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (22投票s)

2008年8月23日

CPOL

4分钟阅读

viewsIcon

643881

downloadIcon

4701

本文介绍了如何为 Windows Mobile 编写自定义的 DirectShow SampleGrabber 过滤器。

引言

本文介绍了如何为 Windows Mobile 编写自定义的 DirectShow SampleGrabber 过滤器。

背景

在我最近的一个项目中,我需要在 .NET CF 中进行一些实时视频分析。然而,.NET API 只允许拍摄静态图像或录制视频,但它没有提供访问视频帧缓冲区的方法,因此我无法即时解析来自摄像头的帧。所以我决定使用 DirectShow API,它对视频流的控制更好,但仍然缺少 Windows 完整 DirectShow 库中可用的 ISampleGrabber 接口。剩下的选择是编写一个自定义的 DirectShow 过滤器,它实现了 ISampleGrabber 接口,允许开发者访问视频缓冲区数据。在本文中,我将尝试解释我在这个过程中学到的东西。

您可以将示例代码作为编写自己过滤器的起点,或者直接使用现成的 SampleGrabber 过滤器并在您的项目中进行使用。网上有许多我用来完成项目的参考资料,但据我所知,目前还没有关于如何完整解决这个问题的“操作指南”。

设置您的 Visual Studio 项目

在您设置 Visual Studio 项目之前,您需要安装 Windows Mobile SDKWindows CE 5.0Windows CE 5.0 Platform builder,其中包含 BaseClasses 库。通常情况下,您不一定会用到 BaseClasses,但它确实能让您的工作轻松很多,所以我加以利用了。

首先创建一个支持 ATL 的 Smart Devices DLL 项目。您还需要将 Windows Mobile SDK 和 Platform Builder 中的头文件添加到您的 include 路径中。

编写过滤器

在这个示例中,我们将使用 TransInPlaceFilter,它是 TransformFilter 的简化版本。我们不需要以任何方式更改数据,只需要将其传递给客户端应用程序。因此,我们创建了一个 CSampleGrabber 类,它还实现了我们自定义的接口以及任何额外的函数。我只添加了 RegisterCallback 函数,它传递来自客户端应用程序的函数指针。每当一个 MediaSample(一个视频帧)通过过滤器时,就会调用此函数,以便客户端可以复制数据并进行一些处理。

// define the filter class
class CSampleGrabber : 
public CTransInPlaceFilter, public ISampleGrabber
{
  private:
  MANAGEDCALLBACKPROC callback;
  long m_Width;
  long m_Height;
  long m_SampleSize;
  long m_Stride;

  public:
  // instantiation
  CSampleGrabber( IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData );
  ~CSampleGrabber();
  static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);

  // IUnknown
  DECLARE_IUNKNOWN;
  STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);

  // CTransInPlaceFilter
  HRESULT CheckInputType(const CMediaType *pmt);
  HRESULT SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt);
  HRESULT Transform(IMediaSample *pMediaSample);
  HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties);
  HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
  HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) {
    return NOERROR; 
    }

  // ISampleGrabber
  STDMETHODIMP RegisterCallback(MANAGEDCALLBACKPROC mdelegate);
};

您可以像其他过滤器一样实现所有接口。有趣的部分是 TransformRegisterCallback 函数。

// Set the client callback
STDMETHODIMP
CSampleGrabber::RegisterCallback( MANAGEDCALLBACKPROC mdelegate ) 
{
    // Set pointer to managed delegate
    callback = mdelegate;
    return S_OK;
}

// Get the pointer to the raw data and pass it to the applications
HRESULT 
CSampleGrabber::Transform(IMediaSample *pMediaSample)
{
    long Size = 0;
    BYTE *pData;

    if ( !pMediaSample )
        return E_FAIL;

    // Get pointer to the video buffer data
    if( FAILED(pMediaSample->GetPointer(&pData)) ) 
        return E_FAIL;
    Size = pMediaSample->GetSize();

    // invoke managed delegate
    if ( callback )
        callback(pData,Size);

    return S_OK;
}

Using the Code

您可以像使用其他任何过滤器一样,直接在您的 DirectShow 应用程序中使用 SampleGrabber 过滤器。在尝试实例化之前注册 DLL 很重要。

// Create and initialize the SampleGrabber filter
CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC, 
		IID_IBaseFilter, (void**)&pSampleGrabber );
m_pFilterGraph->AddFilter( pSampleGrabber, FILTERNAME );

// Get a pointer to the ISampleGrabber interface
pSampleGrabber->QueryInterface( IID_ISampleGrabber, (void**)&m_pISampleGrabber );

// Register the client callback
if ( m_pISampleGrabber )
  m_pISampleGrabber->RegisterCallback( &CGraphBuilder::OnSampleProcessed );

当客户端接收到帧样本时,应尽快将其复制到本地缓冲区并返回。这使得过滤器可以继续执行,而无需等待客户端处理数据,从而大大减慢整个图的运行速度。

您也可以创建一个 C++ DLL 来创建和管理过滤器图,并通过 P/Invoke 从您的 .NET CF 应用程序中调用它。直接在 .NET CF 中创建过滤器图可能会有些棘手,因为 .NET CF 缺乏 C++ .NET 支持,但也许是可能的。

在线参考

历史

  • 2008年8月23日 创建文章
  • 2008年8月26日 v1.1 创建。
    修复
    • Release 现在可以成功构建,添加了 NonDelegatingRelease 的定义。
    • 包含 C++ 和 C# 客户端应用程序,展示了如何使用该过滤器。
    • 示例代码现在可以在 WM SDK 5 下编译。
  • 28.11.2008
    • 添加了更多示例代码:CameraCaptureDLL 项目包含 CameraCapture 示例和内置的 SampleGrabber 过滤器。TestCameraCapture 项目是一个 C# 应用程序示例,它使用该过滤器来获取实时帧数据。
    • 注意:示例代码演示了基本概念,但其中存在一些问题。例如,在尝试停止过滤器图时可能会卡住。这是由于在您尝试停止时过滤器仍在处理数据(抱歉,我没有时间修复这个问题)。尽管存在 bug,但您应该能够获取到摄像头的图像数据。
© . All rights reserved.