DirectShow SDK笔记【关于DirectShow(3)】(转载)

转载 2007年10月14日 13:29:00

 转自http://blog.csdn.net/laiyiling/archive/2006/11/10/1378282.aspx

4.3 Filter States

    Filter有三种状态,停止,暂停,运行。暂停状态是为了在GraphCue Data, 使得运行命令可以立即响应。Filter Graph Manager控制着所有状态的转换。当应用程序调用IMediaControlRun, Pause, Stop方法时, Filter Graph Manager就调用所有Filter的相应IMediaFilter方法。停止,运行状态的切换总是要经过暂停,因此,当应用程序对停止的Graph 调用RUN命令时,Filter图表管理器在Run之前首先要暂停。对于大多数的Filter来说,RunningPaused状态是一样的。考虑如下的Filter Graph:
    Source -> Transform -> Renderer
    假定Source Filter不是实时源。当Source Filter暂停,它创建一个线程生成新的数据并尽可能快的写入到Media Samples. 线程通过调用Transform Filter的输入PIN上的IMemInputPin Receive方法把数据向下推。Transform Filter接收到在Source Filter的线程中的Sample.它可能用一个工作线程把Sample递送给Renderer,但是通常是在同一个线程完成。此时Renderer暂停,它等待接收Sample. 在接收到一个Sample后,它就阻塞线程并不定的保存数据。如果是视频Renderer, Sample作为张贴图像显示,如果必要就重画图像。
    现在,数据流完全准备好进行提交。如果Graph保持暂停,在第一帧SampleSample就堆积在Graph, 直到每个Filter都阻塞在ReceiveGetBuffer. 但是不会有数据丢失。一旦Source线程非阻塞,它简单从阻塞的点恢复。
    Source FilterTransform Filter忽略从暂停到运行的变换,它们简单的尽可能快的继续处理数据。当Render开始运行,它就开始提交Sample. 首先提交的就是当它阻塞时保存的Sample. 然后,每次都接收到新Sample. 计算Sample的提交时间。(细节可参考Time and Clocks in DirectShow),Render会保存每个Sample直到提交时间,到点后再提交Sample. 当它等待提交时间时,线程也阻塞在Receive方法,或者在工作线程用队列接收Sample. Renderer向上的所有Filter都不会陷于时间安排。
    实时源(比如捕捉设备)与普通结构有些不同。在实时源中,不合适提前准备任何数据。应用程序可能暂停Graph,在运行前等待比较长的时间。Graph不应该提交过时Sample. 因此,暂停时实时源不会产生数据,只有运行时才有。为了把事件通知给Filter Graph Manager, Source FilterIMediaFilter方法GetState返回VFW_S_CANT_CUE。此返回值表示Filter已经转换到暂停状态,即使Renderer没有接收到任何数据。
    当一个Filter停止时,它拒绝发送给它的任何SamplesSource Filter关闭他们的Stream线程,其他Filter也关闭他们创建的工作线程,PinDecommit他们的内存分配器。
 
    4.3.1   State Transitions
    Filter Graph Manager按照逆流的方向来切换Filter的状态,从Renderer FilterSource Filter,这种方式可以防止死锁和Sample的丢失。最关键的状态切换是暂停和停止之间。
    ·从停止到暂停,当Filter暂停时就准备好了从连接Filter接收SampleSource Filter是最后一个暂停的。它创建Streaming线程发送Sample,因为下游的Filter的状态都已经切换到暂停了,所以,所有的Filter都可以接收Sample。只有当Graph所有的Renderer都接收到SampleFilter Graph Manager才算完成了状态的切换(除了前面讲的实时源例外)
    ·从暂停到停止。当Filter停止时它要释放它拥有的所有的Sample以使得上一级Filter中的IMemAllocator::GetBuffer调用脱离阻塞。如果FilterReceive函数中等待资源,它也会停止等待,并从Receive返回,以使调用Filter解锁。因此,当Filter Graph Manager停止连接的上一级Filter时,Filter就不会在GetBufferReceive函数中阻塞,也就能响应停止命令。上级Filter在得到停止命令前可以会递送一些额外Sample。但是下级Filter可能拒绝他们,因为他们已经停止。
    4.4 Pull Model
IMemInputPin接口中,上级Filter决定发送什么样数据,然后将数据推给下Filter。但对某些Filter,拉模式更适合。现在,下Filter向上Filter请求数据。数据依然是从上级到下级,从输出Pin到输入Pin,但是由下Filter发动数据流动。这种类型连接采用的是IAsyncReader接口。
   拉模式的典型应用是文件回放。例如在AVI文件的回放Graph中,Async File Source Filter就执行通用文件读写操作,然后将数据以字节流的方式(不带格式信息)发送给下FilterAVI Splitter读取AVI头并把数据流分析为视频、音频流。AVI Splitter能比Async File Source Filter更好的决定它需要什么类型的数据,因此它用IMemInputPin代替IAsyncReader接口。
    为了从输出PIN请求数据,输入PIN调用如下一种方法:
    ·IAsyncReader::Request
    ·IAsyncReader::SyncRead
    ·IAsyncReader::SyncReadAligned
    第一个方法是异步的,支持多个重叠读写。其他是同步的。
    理论上,任何Filter可以支持IAsyncReader,但是实际上它被设计来连接Source FilterParser FilterParser的功能与推模式中的Source Filter非常相同。当它暂停时,创建一个数据流线程从IAsyncReader连接拉数据,并推向下一级。输出PIN使用IMemInputPinGraph的余下部分使用标准的推模式。
 
5. Event Notification in DirectShow
 
    5.1 Overview of Event Notification
    某个事件发生时,比如数据流结束,产生一个错误,提交流失败等,Filter就给Filter Graph Manager发送一个事件通知。Filter Graph Manager自己处理部分事件,另一部分交给应用程序处理。如果Filter Graph Manager没有处理事件,它就把事件通知放入到一个队列中。图表管理器也可以将自己的事件通知放进队列中。
    应用程序以事件队列获取事件并根据事件类型进行处理。DirectShow中的事件通知和Windows的消息机制差不多。应用程序也可以取消Filter Graph Manager特定事件的默认行为。Filter Graph Manager就直接把事件放入队列,留给应用程序来处理。
 
    5.2 Retrieving Events
    Filter Graph Manager暴露了三个接口处理事件通知:
    ·IMediaEventSink  Filter用这个接口来Post事件。
    ·IMediaEvent       应用程序利用这个接口来从队列中查询消息。
    ·IMediaEventEx     IMediaEvent的扩展。
    Filter通过IMediaEventSink::Notify方法向Filter Graph Manager提交事件。事件通知包括一个事件Code,这个Code不仅仅代表了事件的类型,还包含两个DWORD类型的参数用来传递一些其他的信息。根据不同的事件Code,附加信息可能是指针、返回码、参考时间或其他信息。获取事件Code和参数的全部列表可参考Event Notification Codes.
    应用程序通过调用IMediaEvent::GetEvent从事件队列中获取事件。如果有事件发生,该函数就返回一个事件码和两个参数,如果没有事件,则一直阻塞直到有事件发生和超过某个时间。调用GetEvent函数后,应用程序必须调用IMediaEvent::FreeEventParams来释放事件码所关联的资源。例如,参数可能是Filter Graph分配的BSTR内存。下面的代码演示了如何从事件队列中提取事件:
long    evCode, param1, param2;
HRESULT hr;
while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))
{
    switch(evCode)
    {
        // Call application-defined functions for each
        // type of event that you want to handle.
    }
    hr = pEvent->FreeEventParams(evCode, param1, param2);
}
    为了重载Filter Graph Manager对事件的缺省处理,可以用某个事件码做参数调用IMediaEventCancelDefaultHandling方法。这样就可以屏蔽Filter Graph Manager对某个事件码的处理了。如果要恢复图表管理器对该事件码的缺省处理,可以调用RestoreDefaultHandling方法。如果Filter Graph对某个事件没有缺省的处理,调用这两个函数是不起作用的。
 
    5.3 Learning When an Event Occurs
    为了处理DirectShow事件,应用程序需要一种机制来知道什么时候队列中有等待的事件。Filter Graph Manager提供了两种方法:
    ·窗口通知:Filter Graph Manager发送开发者自己定义的窗口消息
    ·事件信号:如果队列中有DirectShow事件,就用事件信号通知应用程序,如果队列为空就重新设置事件信号。
    应用程序可以使用这两种技术。窗口通知通常更简单。
 
    5.3.1   Window Notification
    建立窗口通知可调用IMediaEventEx::SetNotifyWindow方法,并指定一个私有消息。应用程序可使用从WM_APP0XBFFF之间的消息值作为私有消息。只要Filter Graph Manager把一个新事件放入到队列时,就向目标窗口发送消息。应用程序从消息队列响应消息。
下面的代码演示了如何利用消息通知:
#define WM_GRAPHNOTIFY WM_APP+1    // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
    消息是一个普通的窗口消息,是从DirectShow的事件通知队列单独提交的。这种方法的好处多数程序已经实现了消息循环。因此,我们可以合并DirectShow的事件通知而不需要过多额外工作。下面的代码说明了如何响应消息通知的框架。完整的例子可参考Responding to Events.
LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
    switch (msg)
    {
        case WM_GRAPHNOTIFY:
            HandleEvent(); // Application-defined function.
            break;
        // Handle other Windows messages here too.
    }
    return (DefWindowProc(hwnd, msg, wParam, lParam));
}
    由于事件通知和窗口的消息循环都是异步的,因此,当你的应用程序处理消息的时候,队列中或许有N个事件等待处理。同样,如果事件失效,它也可能从事件队列清除掉。因此,在你调用GetEvent的时候,一定要循环调用,直到返回一个错误码,这表明队列是空的。
    当你释放IMediaEventEx指针时,你可以调用SetNotifyWindow来取消事件通知,记住此时要给这个函数传递一个NULL指针。在你的事件处理程序中,在调用GetEvent之前一定要检查IMediaEventEx指针是否为空,这样就可以避免错误。因为有时在释放IMediaEventEx指针后可能会得到通知。
 
    5.3.2   Event Signaling
    Filter Graph Manager里有一个手动设置的Event内核对象,用来反映事件队列的状态。如果队列中有等待处理的事件,Event就处于通知状态,如果队列是空的,IMediaEvent::GetEvent函数调用就会重置该Event对象。应用程序可利用此事件来判断队列的状态。
    应用程序可以调用IMediaEvent::GetEventHandle获得Event内核对象的句柄,然后就可以调用WaitForMultipleObjects来等待事件的发生,如果Event被通知了,就可以调用GetEvent来获得DirectShow的事件。下面的代码演示了事件信号。返回事件句柄,再等待1000毫秒。如果事件变为信号状态,调用GetEvent返回事件Code和参数。获取到EC_COMPLETE事件Code时表示回放结束中止循环:
HANDLE hEvent;
long    evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr)
{
    /* Insert failure-handling code here. */
}
while(!bDone)
{
    if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
    {
        while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))
        {
            printf("Event code: %#04x/n Params: %d, %d/n", evCode, param1, param2);
            pEvent->FreeEventParams(evCode, param1, param2);
              switch (evCode)
             {
              case EC_COMPLETE: // Fall through.
              case EC_USERABORT: // Fall through.
             case EC_ERRORABORT:
             CleanUp();
             PostQuitMessage(0);
             return;
             }
        }
    }
}
 

win10 + VS2013下载directshow相关示例代码及directshow库文件调用

最近需要做虚拟摄像头,网上下载了一个现成的代码调试,用directshow,记录一下环境配置和修改部分,给有需要的朋友 1,环境配置:下载dierectshow vs2013可以自行扩展下载相关代码,...
  • u011668104
  • u011668104
  • 2016年11月14日 19:26
  • 2950

Win7下设置DirectShow编译环境小结(特别的x64位环境)

1. 下载DirectShow 由于现在directShow没有和direcxtx一起发布,而是和windows sdk 打包发布了,Windows SDK 7.1 地址:http://www.mic...
  • dijkstar
  • dijkstar
  • 2016年03月19日 22:32
  • 2718

Directshow学习笔记五-----一个简单的视频播放程序(个人学习总结,仅供参考)

1.       建立一个Filter Graph Manager的实例. 2.       使用Filter Graph Manager 建立一个filter graph. 3.       运...
  • afu1972715000
  • afu1972715000
  • 2015年01月10日 14:24
  • 585

什么是DirectX,DirectShow与DirectX有什么区别?

在介绍同三维万能高清视频采集卡和全能音视频解码编码器软件等多媒体软件时,我们多次提到DirectShow、DirectX,那么什么是DirectShow?什么是DirectX,DirectShow与D...
  • wishfly
  • wishfly
  • 2015年10月17日 23:44
  • 986

关于DirectShow SDK版本变迁说明及解决找不到streams.h文件

1.DirectShow SDK版本变迁说明 做视频聊天和视频播放器程序的时候会涉及到使用DirectShow SDK,原本DirectShow SDK是集成在DirectX中,但自从DirectX ...
  • u011028345
  • u011028345
  • 2017年02月18日 19:34
  • 822

Directshow开发笔记

摘要:本篇文档主要描述关于用Directshow进行视频开发的一些技术 主要包括下面内容 1关于视频捕捉(About Video Capture in Dshow)  2选择一个视频捕捉设备...
  • fin86889003
  • fin86889003
  • 2014年04月01日 17:57
  • 372

配置DirectShow开发环境(VS2010,64位Win8系统)

配置DirectShow开发环境(VS2010,64位Win8系统) 目前,新版的DirectShow并没有包括在DirecxtX中一起发布,而是和Windows SDK一起打包发布,因此首先要下载...
  • iw1210
  • iw1210
  • 2016年03月20日 14:27
  • 1985

一个清华学子写的关于directshow的学习心得【转】

学习DirectShow有一段时间了,把这段学习过程中翻译出来的SDK与大家分享,同时也希望专家们指出我理解上的错误,万分感谢。 1. DirectShow介绍     DirectShow是一个wi...
  • wishfly
  • wishfly
  • 2015年11月18日 10:30
  • 9806

c++ DirectShow播放任意格式的视频

利用opencv只能处理.avi的视频,opencv之前的版本之前试过好像是只能处理.avi未压缩版本的视频,未压缩过的视频相当大,一个文件大概是几十个G。(这个不确定,因为之前用的压缩过的.avi的...
  • KUAILE123
  • KUAILE123
  • 2013年09月08日 16:29
  • 2213

DirectShow 开发环境搭建(整理)

directshow sdk 开发32位程序,用GRMSDK_EN_DVD.iso, 开发64位程序,用GRMSDKX_EN_DVD.iso。 找到Samples\Multimedia\Di...
  • 91program
  • 91program
  • 2014年05月20日 16:16
  • 1775
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:DirectShow SDK笔记【关于DirectShow(3)】(转载)
举报原因:
原因补充:

(最多只允许输入30个字)