1. 业奇农业网 > 百科 >

如何从

编写 Grabber 筛选器示例

如何从

从 DirectShow 筛选器图形获取数据的一个简单方式是编写一个自定义“grabber”筛选器示例。将该筛选器与您要监视的数据流进行连接,然后运行筛选器图形。当数据通过筛选器进行传递时,应用程序会根据您的想法对数据进行操作。

这些 grabber 筛选器示例的可能用途包括:

将整个文件解码到内存缓冲区。

从视频文件获取一个贴帧。

从实时视频流获取静态图像。

将视频文件解码到 Microsoft DirectDraw? 缓冲区中。

DirectShow 8.0 SDK 包括了一个 grabber 筛选器示例,但是没有提供源代码。DirectShow 8.1 SDK 则包括了这个 grabber 筛选器示例改进版本的源代码,作为一个 SDK 示例,其名称为 GrabberSample Filter Sample。

从何处开始?

首先您要选择是编写转换筛选器还是输出程序。转换筛选器可以连接另一个下游筛选器,使您能够呈现数据、将其写入文件,以及执行其他操作。但是因为转换筛选器需要一个附加的下游连接,所以要使其正确实现可能更复杂一些。输出程序筛选器则只需要一个输入连接。

本文将说明如何编写一个转换筛选器,但是很多理念同样适用于输出程序筛选器。

本文讲述的这个筛选器是一个“就地转换”筛选器,这就表示它会直接在它接收的缓冲区中修改数据,而不会创建新缓冲区的副本。它使用 DirectShow 基类库。

要编写一个就地转换筛选器,请执行下列步骤:

1.

定义一个从 CTransInPlaceFilter 类派生的新类。

2.

您可以使筛选器成为一个能够执行自注册的真正的 COM 对象。为此,您需要一个带有 CLSID 定义的 IDL 文件或标头文件,一个导出 DLL 函数的 DEF 文件,还需要一个静态类方法,才能创建筛选器。有关详细信息,请参阅 DirectShow SDK 文档中有关如何创建 DLL 和如何注册 DirectShow 筛选器的主题。

3.

重写 CTransInPlaceFilter 中的两个纯虚拟方法:Transform 方法和 CheckInputType 方法。

CTransInPlaceFilter 类会自动处理大量其他任务,例如:协商针连接和缓冲器,在必要时重新连接针,将数据从输入针移动到输出针,以及支持多个线程。阅读这些基类的 C++ 代码是了解 DirectShow 筛选器更多详细信息的一种很好的方法。如果您想执行一些更复杂的操作,可能需要重写 CTransInPlaceFilter 的其他方法。

重写 CheckInputType 方法

筛选器中的 CheckInputType 方法决定了要接受哪些媒体类型,要拒绝哪些媒体类型。在针连接过程中,上游针会提出各种媒体类型。您的筛选器可以接受任何媒体类型,也可以拒绝任何媒体类型。DirectShow 在构建筛选器图形时,会自动尝试找出注册表中列出的筛选器,以使得连接能够运行。例如,如果您的筛选器只接受未压缩的视频,则当应用程序尝试将其连接到一个 AVI 文件源时,DirectShow 会插入相应的视频解压缩程序。

格式类型

如果您的筛选器只接受带有子类型 MEDIASUBTYPE_RGB24 的 MEDIATYPE_Video,则无需与 FORMAT_VideoInfo 格式类型进行连接。还存在几个其他的视频格式类型,其中包括 Format_VideoInfo2 和 FORMAT_DvInfo。您必须决定筛选器要处理哪些格式,以及相应接受或拒绝哪些不同的格式类型。

格式块和反转的 DIB

对于未压缩的视频类型,上游筛选器可能要传递反转的设备无关位图 (DIB)。在连接时,它会在格式块的 BITMAPINFOHEADER 结构的 biHeight 成员中指定上述内容。因此,如果您的筛选器需要一种特定的 DIB 方向(反转或不反转),则请确保检查 biHeight 成员,并拒绝筛选器不会处理的任何类型。

很多解压缩器都可以使用两个方向进行解码,并且会同时建议两种类型。如果您不检查方向就接受媒体类型,这些针则会使用解压缩器提出的第一个方向进行连接。

在应用程序中设置媒体类型

在 grabber 筛选器示例中,让应用程序来控制筛选器接受哪些媒体类型比较有意义。应用程序使用这种方式可以执行下列步骤:

1.

应用程序针对筛选器调用一个自定义方法,来指定您想要的数据类型。这可以是一种具体的格式,也可能是允许一些可能格式的通用说明(例如,任何大小的 24 位 RGB 视频)。

2.

应用程序将该 grabber 示例与图形中的其他筛选器进行连接。在针协商过程中,CheckInput 方法尝试将建议的媒体类型与应用程序在第一步中指定的类型进行匹配。

3.

该应用程序调用另一个自定义方法来检索真正用于该连接的媒体类型。

例如,在第一步中,应用程序可能指定了 24 位 RGB。在第二步中,这些针将要使用一个特定的视频大小进行连接,如 320 X 240 像素。在第三步中,应用程序检索媒体类型,以确定视频大小。如果没有此信息,应用程序则无法解释接收到的数据。

您必须在筛选器上定义一个包含这两个方法的自定义 COM 接口。DirectShow Grabber 筛选器示例使用的是 ISampleGrabber 接口;创建您自己的筛选器时,您可以将其用作指南。

重写转换方法

CTransInPlaceFilter 构造函数方法的其中一个参数是指定筛选器是否修改它所接收的数据的标志。如果您传递值 false,则不得以任何方式更改数据。否则,可以在Transform 方法中任意修改数据。

Transform 方法会接收一个指向媒体示例 IMediaSample 接口的指针。这种方法称为 CTransInPlaceFilter::Receive 方法。在 Transform 方法返回之后,Receive方法会针对输出针调用 CbaseOutputPin::Deliver,以传递该示例。

如果 Transform 方法返回 S_FALSE,该基类则会发出一个质量控制更改信号。但是,在本例中,Receive 方法返回了 S_OK(而不是 S_FALSE),因此上游筛选器继续传递。如果 Transform 方法返回错误代码,该基类则会向筛选器图形发出一个流式处理错误信号,而且筛选器图形停止。除非有真正的流式处理错误,否则不应返回错误代码。如果您只是想停止该流,则应该重写 Receive 方法,并从 Receive 返回 S_FALSE。

返回页首

使用多线程处理

您的应用程序运行所基于的线程总是应该与向筛选器传递数据的线程不同。如果您想在应用程序中同步检索数据,则必须考虑这种多线程处理。下面是用于处理一些常见情况的建议:

解码整个文件

如果您想要解码整个压缩文件,并按照顺序获取每个未压缩的数据块,则可能不需要担心线程处理的问题。在应用程序中创建一个全局缓冲区,编写 Transform 方法,以便它写入该缓冲区。另外,还可以让 Transform 每当接收示例时都调用一个回调方法。在该回调方法中写入全局缓冲区。在您的应用程序中,设置该回调,运行图形直到停止,这样就完成了此过程。

解码部分文件

这种情况与解码整个文件相似,只是应用程序需要使用 IMediaSeeking::SetPositions 方法来设置开始和停止位置。还有一种方法是,从 Receive 方法返回 S_FALSE,以便向源筛选器发送停止传递数据的信号。

解码文件的随机部分

如果您想要解码文件的一部分,然后搜索另一个位置再进行解码,这个过程就变得更复杂了。当您搜索筛选器图形,或者从一种图形状态更改为另一种图形状态时,应用程序必须等待图形状态变为稳定状态。

当您搜索图形(使用 IMediaSeeking 或 IMediaPosition)时,首先会从输出程序筛选器启动调用,然后向上游进行同步移动,直到到达源筛选器。源筛选器会异步 停止推数据,向下游发送刷新,搜索新的位置,然后再次开始发送数据。

要获取单个数据帧,请重写 Receive 方法,以返回 S_FALSE。在应用程序中,暂停该图形,并搜索到所需的时间。该源将通过搜索进行响应,然后它会向下游发送一个示例。

如果您希望应用程序同步处理示例,而不是进行异步处理,则请使用事件。在 Transform 方法中设置事件,并在应用程序中等待该事件。例如,您可以使用一个如下所示的循环:

while (not done)

Seek the filter graph.

Wait for the event to be signaled.

此示例假设您完全在 Transform 方法内部或者回调方法内部处理数据。如果您希望在该应用程序循环中处理数据,则需要第二个事件。

while (not done)

Seek the filter graph.

Wait for event 1 to be signaled.

Process the data.

Signal event 2.

编写筛选器的 Transform 方法,如下所示:

Transform:

Signal event 1.

Wait for event 2.

Return S_FALSE.

如果没有第二个事件,Transform 方法则会立即返回,这是因为它是在另外一个线程上运行的。然后,其他筛选器可能会在应用程序仍然处理旧数据的同时向该示例写入新的数据。

注 还有一个选择就是,在 Transform 方法中针对该示例调用 AddRef,然后在应用程序中针对该示例调用 Release。通过在示例中保留一个参考数,可以防止它返回到“可用”列表。但是,这样无法阻止下游示例修改该示例。有关参考计数和 IMediaSample 接口的详细信息,请参阅 SDK 文档中的“示例和分配器”主题。

返回页首

应用程序代码示例

下面的代码是一个使用 grabber 筛选器示例的控制台应用程序:

#include "stdafx.h"

#include <atlbase.h>

#include <streams.h>

#include <qedit.h> // for Null Renderer

#include <filfuncs.h> // for GetOutPin, GetInPin

#include <filfuncs.cpp> // for GetOutPin, GetInPin

#include "SampleGrabber.h"

int test(int argc, char* argv[]);

int main(int argc, char* argv[])

{

CoInitialize( NULL );

int i = test( argc, argv );

CoUninitialize();

return i;

}

HANDLE gWaitEvent = NULL;

HRESULT Callback(IMediaSample* pSample, REFERENCE_TIME* StartTime,

REFERENCE_TIME* StopTime)

{

// Note: We cannot do anything with this sample until we call

// GetConnectedMediaType on the filter to find out the format.

DbgLog((LOG_TRACE, 0, "Callback with sample %lx for time %ld",

pSample, long(*StartTime / 10000)));

SetEvent(gWaitEvent);

return S_FALSE; // Tell the source to stop delivering samples.

}

int test( int argc, char * argv[] )

{

// Create an event, which is signaled when we get a sample.

gWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

// The sample grabber is not in the registry, so create it with 'new'.

HRESULT hr = S_OK;

CSampleGrabber *pGrab = new CSampleGrabber(NULL, &hr, FALSE);

pGrab->AddRef();

// Set the callback function of the filter.

pGrab->SetCallback(&Callback);

// Set up a partially specified media type.

CMediaType mt;

mt.SetType(&MEDIATYPE_Video);

mt.SetSubtype(&MEDIASUBTYPE_RGB24);

hr = pGrab->SetAcceptedMediaType(&mt);

// Create the filter graph manager.

CComPtr<IFilterGraph> pGraph;

hr = pGraph.CoCreateInstance( CLSID_FilterGraph );

// Query for other useful interfaces.

CComQIPtr<IGraphBuilder, &IID_IGraphBuilder> pBuilder(pGraph);

CComQIPtr<IMediaSeeking, &IID_IMediaSeeking> pSeeking(pGraph);

CComQIPtr<IMediaControl, &IID_IMediaControl> pControl(pGraph);

CComQIPtr<IMediaFilter, &IID_IMediaFilter> pMediaFilter(pGraph);

CComQIPtr<IMediaEvent, &IID_IMediaEvent> pEvent(pGraph);

// Add a source filter to the graph.

CComPtr<IbaseFilter> pSource;

hr = pBuilder->AddSourceFilter(L"C:test.avi", L"Source", &pSource);

// Add the sample grabber to the graph.

hr = pBuilder->AddFilter(pGrab, L"Grabber");

// Find the input and output pins, and connect them.

IPin *pSourceOut = GetOutPin(pSource, 0);

IPin *pGrabIn = GetInPin(pGrab, 0);

hr = pBuilder->Connect(pSourceOut, pGrabIn);

// Create the Null Renderer filter and add it to the graph.

CComPtr<IbaseFilter> pNull;

hr = pNull.CoCreateInstance(CLSID_NullRenderer);

hr = pBuilder->AddFilter(pNull, L"Renderer");

// Get the other input and output pins, and connect them.

IPin *pGrabout = GetOutPin(pGrab, 0);

IPin *pNullIn = GetInPin(pNull, 0);

hr = pBuilder->Connect(pGrabout, pNullIn);

// Show the graph in the debug output.

DumpGraph(pGraph, 0);

// Note: The graph is built, but we do not know the format yet.

// To find the format, call GetConnectedMediaType. For this example,

// we just write some information to the debug window.

REFERENCE_TIME Duration = 0;

hr = pSeeking->GetDuration(&Duration);

BOOL Paused = FALSE;

long t1 = timeGetTime();

for(int i = 0 ; i < 100 ; i++)

{

// Seek the graph.

REFERENCE_TIME Seek = Duration * i / 100;

hr = pSeeking->SetPositions(&Seek, AM_SEEKING_AbsolutePositioning,

NULL, AM_SEEKING_NoPositioning );

// Pause the graph, if it is not paused yet.

if( !Paused )

{

hr = pControl->Pause();

ASSERT(!FAILED(hr));

Paused = TRUE;

}

// Wait for the source to deliver a sample. The callback returns

// S_FALSE, so the source delivers one sample per seek.

WaitForSingleObject(gWaitEvent, INFINITE);

}

long t2 = timeGetTime();

DbgLog((LOG_TRACE, 0, "frames per second = %ld", i * 1000/(t2 - t1)));

pGrab->Release();

return 0;

}

CAN通信筛选器作用

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

有加这句话了么?

通信筛选器只是简单的过滤器,用于限制数据记录仪记录的数据,根据数据的重要性,接收端可以专注于重要消息。can通信系统就是用can完成传输信息传输的系统。

基本介绍

can 是controller area network 的缩写(以下称为can),是iso国际标准化的串行通信协议。在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个lan,进行大量数据的高速通信”的需要,1986 年德国电气商博世公司开发出面向汽车的can 通信协议。此后,can 通过iso11898 及iso11519 进行了标准化,在欧洲已是汽车网络的标准协议。 can 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设备、工业设备等方面。现场总线是当今自动化领域技术发展的热点之一,被誉为自动化领域的计算机局域网。它的出现为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有力的技术支持。

本文由用户上传,如有侵权请联系删除!转转请注明出处:https://nongye.s666.cn/bk/6_6571937604.html