DirectShow系列讲座之二——Filter原理

2023-11-19

在上一讲中,笔者介绍了DirectShow的总体系统框架。从这一讲开始,我们要从程序员的角度,进一步深入探讨一下DirectShow的应用以及Filter的开发。
在这之前,笔者首先要特别提一下微软提供的一个Filter测试工具——GraphEdit,它的路径在DXSDK/bin/DXUtils/GraphEdit.exe。(如果您还没有安装DirectX SDK,请到微软的网站上去下载。)通过这个工具,我们可以很直观地看到Filter Graph的运行及处理流程,方便我们进行程序调试。(如果您手边就有电脑,还等什么,马上体验一下吧:运行GraphEdit,执行File->Render Media File…选择一个媒体文件;当Filter Graph构建成功后,按下工具栏的运行按钮;您就能看到刚才选择的媒体文件被回放出来了!看到了吧,写一个媒体播放器也就这么回事!)
接下去,我们开讲Filter的开发。
学习DirectShow Filter的开发,不外乎以下几种方法:看帮助文档、看示例代码和看SDK基类源代码。看帮助文档,应着重于总体概念上的理解;看示例代码应与基类源代码的研究同步进行,因为自己写Filter,关键的第一步是选择一个合适的Filter基类和Pin的基类。对于Filter的把握,一般认为要掌握以下三方面的内容:Filter之间Pin的连接、Filter之间的数据传输以及流媒体的随机访问(或者说流的定位)。下面就开始分别进行阐述。
所谓的Filter Pin之间的连接,实际上是Pin之间Media Type(媒体类型)的一个协商过程。连接总是从输出Pin指向输入Pin的。要想深入了解具体的连接过程,就必须认真研读SDK的基类源代码(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/amfilter.cpp,类CBasePin的Connect方法)。连接的大致过程为,枚举欲连接的输入Pin上所有的媒体类型,逐一用这些媒体类型与输出Pin进行连接,如果输出Pin也接受这种媒体类型,则Pin之间的连接宣告成功;如果所有输入Pin上枚举的媒体类型输出Pin都不支持,则枚举输出Pin上的所有媒体类型,并逐一用这些媒体类型与输入Pin进行连接。如果输入Pin接受其中的一种媒体类型,则Pin之间的连接到此也宣告成功;如果输出Pin上的所有媒体类型,输入Pin都不支持,则这两个Pin之间的连接过程宣告失败。
有一点需要注意的是,上述的输入Pin与输出Pin一般不属于同一个Filter,典型的是上一级Filter(也叫Upstream Filter)的输出Pin连向下一级Filter(也叫Downstream Filter)的输入Pin。如下图所示:



当Filter的Pin之间连接完成,也就是说,连接双方通过协商取得了一种大家都支持的媒体类型之后,即开始为数据传输做准备。这些准备工作中,最重要的是Pin上的内存分配器的协商,一般也是由输出Pin发起。在DirectShow Filter之间,数据是通过一个一个数据包传送的,这个数据包叫做Sample。Sample本身是一个COM对象,拥有一段内存用以装载数据,Sample就由内存分配器(Allocator)来统一管理。已成功连接的一对输出、输入Pin使用同一个内存分配器,所以数据从输出Pin传送到输入Pin上是无需内存拷贝的。而典型的数据拷贝,一般发生在Filter内部,从Filter的输入Pin上读取数据后,进行一定意图的处理,然后在Filter的输出Pin上填充数据,然后继续往下传输。下面,我们就具体阐述一下Filter之间的数据传送。
首先,大家要区分一下Filter的两种主要的数据传输模式:推模式(Push Model)和拉模式(Pull Model)。参考图如下:


  
所谓推模式,即源Filter(Source Filter)自己能够产生数据,并且一般在它的输出Pin上有独立的子线程负责将数据发送出去,常见的情况如代表WDM模型的采集卡的Live Source Filter;而所谓拉模式,即源Filter不具有把自己的数据送出去的能力,这种情况下,一般源Filter后紧跟着接一个Parser Filter或Splitter Filter,这种Filter一般在输入Pin上有个独立的子线程,负责不断地从源Filter索取数据,然后经过处理后将数据传送下去,常见的情况如文件源。推模式下,源Filter是主动的;拉模式下,源Filter是被动的。而事实上,如果将上图拉模式中的源Filter和Splitter Filter看成另一个虚拟的源Filter,则后面的Filter之间的数据传输也与推模式完全相同。
那么,数据到底是怎么通过连接着的Pin传输的呢?首先来看推模式。在源Filter后面的Filter输入Pin上,一定实现了一个IMemInputPin接口,数据正是通过上一级Filter调用这个接口的Receive方法进行传输的。值得注意的是(上面已经提到过),数据从输出Pin通过Receive方法调用传输到输入Pin上,并没有进行内存拷贝,它只是一个相当于数据到达的“通知”。再看一下拉模式。拉模式下的源Filter的输出Pin上,一定实现了一个IAsyncReader接口;其后面的Splitter Filter,就是通过调用这个接口的Request方法或者SyncRead方法来获得数据。Splitter Filter然后像推模式一样,调用下一级Filter输入Pin上的IMemInputPin接口Receive方法实现数据的往下传送。深入了解这部分内容,请认真研读SDK的基类源代码(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/source.cpp和pullpin.cpp)。
下面,我们来讲一下流的定位(Media Seeking)。在GraphEdit中,当我们成功构建了一个Filter Graph之后,我们就可以播放它。在播放中,我们可以看到进度条也在相应地前进。当然,我们也可以通过拖动进度条,实现随机访问。要做到这一点,在应用程序级别应该可以知道Filter Graph总共要播放多长时间,当前播放到什么位置等等。那么,在Filter级别,这一点是怎么实现的呢?
我们知道,若干个Filter通过Pin的相互连接组成了Filter Graph。而这个Filter Graph是由另一个COM对象Filter Graph Manager来管理的。通过Filter Graph Manager,我们就可以得到一个IMediaSeeking的接口来实现对流媒体的定位。在Filter级别,我们可以看到,Filter Graph Manager首先从最后一个Filter(Renderer Filter)开始,询问上一级Filter的输出Pin是否支持IMediaSeeking接口。如果支持,则返回这个接口;如果不支持,则继续往上一级Filter询问,直到源Filter。一般在源Filter的输出Pin上实现IMediaSeeking接口,它告诉调用者总共有多长时间的媒体内容,当前播放位置等信息。(如果是文件源,一般在Parser Filter或Splitter Filter实现这个接口。)对于Filter开发者来说,如果我们写的是源Filter,我们就要在Filter的输出Pin上实现IMediaSeeking这个接口;如果写的是中间的传输Filter,只需要在输出Pin上将用户的获得接口请求往上传递给上一级Filter的输出Pin;如果写的是Renderer Filter,需要在Filter上将用户的获得接口请求往上传递给上一级Filter的输出Pin。进一步的了解,请认真研读SDK的基类源代码(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/transfrm.cpp的类方法CTransformOutputPin::NonDelegatingQueryInterface实现和ctlutil.cpp中类CPosPassThru的实现)。
以上我们介绍了一下如何学习DirectShow Filter开发,以及一些开始写自己的Filter之前的预备知识。下一讲,笔者将根据自己开发Filter的经验,手把手教你如何写自己的Filter。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DirectShow系列讲座之二——Filter原理 的相关文章

  • 使用 D3.js SVG 进行 2D 多边形布尔运算

    我有 2 个使用 D3 js 创建的简单面积图 数据和代码如下 让我们称它们为Graph A Graph B 我想用它们根据它们的相交方式创建 3 个新路径 多边形 Path 1 Graph A Graph B Path 2 Graph B
  • 使用嵌套数组过滤对象数组

    所以我试图在对象数组上设置嵌套过滤器 问题是过滤器应用在对象内部的另一个对象数组的键上 这是代码 const items name 123 id 1 value true arr id 1 name 456 id 2 value false
  • Python 日志记录在 ini 文件中为处理程序添加过滤器?

    我有一个像这样的 log ini handler info class StreamHandler level INFO formatter fmt filter infofilter args sys stdout handler err
  • 将边权重传递给networkx中的graphviz_layout

    每个人都找不到如何将权重列表的属性名称传递给networkx中的graphviz layout 像这样的事情 nx spring layout G weight weight sum 但与nx graphviz layout G 也许有人会
  • 如何使用 RDFLib 解析大数据集?

    我正在尝试使用 RDFLib 3 0 解析几个大图 显然它处理第一个图并在第二个图上死掉 MemoryError 看起来 MySQL 不再支持作为存储 您能建议一种以某种方式解析这些图的方法吗 Traceback most recent c
  • ActiveAdmin:按子对象计数过滤

    在严重依赖 ActiveAdmin 的 Ruby on Rails 应用程序中 我有一个赞助商模型 它与赞助商模型关联 一sponsor可以资助很多孩子 所以一个sponsor可以有很多sponsorships 我想做的是能够在赞助商索引页
  • 为什么使用 Dijkstra 算法而不是最佳(最便宜)优先搜索?

    从我到目前为止所读到的来看 这最佳优先搜索 https en wikipedia org wiki Best first search在找到到达目标的最短路径方面似乎更快 因为 Dijkstra 算法在遍历图时必须放松所有节点 是什么让 D
  • Primefaces 中的过滤数据表仅有效一次

    我正在尝试使用 Primefaces 过滤数据表 就像这个例子 http www primefaces org showcase ui datatableFiltering jsf 在网络浏览器中 我输入要过滤的文本 它会工作一次 但是当我
  • 如何在 Excel 中创建时间范围图表

    Can anyone help me create graph of time ranges of all elements in Excel My data looks like this 连接时间和断开连接时间数据值采用 24 小时格式
  • 使用组合框过滤文本框

    好吧 我必须创建一个表单 它获取文件夹的内容并将其列出在文本框中 是的 文本框不是列表框 然后 我必须使用包含文件夹所有扩展名的组合框来过滤此文本框 例如 如果我在组合框中选择 txt 则文本框应过滤以仅显示所有文本文件 除了让组合框过滤文
  • 在 python matplotlib 中格式化损坏的 y 轴

    我正在 matplotlib 中处理一个 相当复杂的 条形图 它包含来自多个源的摘要数据 每个源都沿 x 轴标记 y 轴上有一系列结果 许多结果都是异常值 我尝试使用断开的 y 轴来显示这些结果 而不会使用以下组合来扭曲整个图表这个方法 h
  • 如何根据开始和结束条件过滤数据?

    我试图根据依赖于连续日期的两个条件来过滤数据 我在寻找对于 5 个以上的连续日期 值低于 2 with a 缓冲期 of 值 2 到 5 最多连续 3 天 它看起来像这样 很抱歉这里的 Excel 尝试很糟糕 第 1 天到第 10 天将包括
  • 使用 d3 在两个节点之间绘制多条边

    我一直在关注 Mike Bostock 的代码这个例子 http bl ocks org 1153292学习如何在 d3 中绘制有向图 并且想知道如何构建代码 以便可以在图中的两个节点之间添加多个边 例如 如果上例中的数据集定义为 var
  • 带回溯的 Dijkstra 算法?

    In a 相关主题 https stackoverflow com questions 28333756 finding most efficient path between two nodes in an interval graph
  • 如何通过单击按钮从反应状态挂钩数组中删除对象

    我正在尝试制作一个按钮 根据传递的索引从数组 即状态 中删除一个对象 我已经尝试了很多 但我的方法都不起作用 所以这是代码 希望我可以找人帮忙 state const items setItems useState name quantit
  • 从字符串开头过滤 ng-repeat 元素

    我正在尝试 AngularJS 这是我的第一次尝试 我正在尝试使用 开头为 而不是 包含 之类的内容来过滤对象数组 但我不明白如何做到这一点 假设我有一个elements像这样的数组 amount 50 amount 25 如果我想过滤5两
  • 如果 1 个 Gremlin 查询中不存在顶点和边,则创建

    我找到以下代码来创建边缘 如果它尚不存在 g V hasLabel V1 has userId userId as a V hasLabel V1 has userId userId2 coalesce bothE link where o
  • 需要帮助在 JavaScript 中过滤数组

    这是我在 JavaScript 中的数组 let myArray Bob Katy Bob Bob Katy 我想通过检查来过滤这个数组如果当前值等于其后或之前的值 我不太确定如何实现这一目标 但是 有人能给我指出一个方向吗 现在我知道如何
  • Android ListView数组索引过滤后越界

    我认为这是专家的问题 我接到电话getView with positon 出界来自ListView数据列表 当我使用适配器过滤器时会发生这种情况 过滤器publishResults 方法使用小于原始列表的过滤列表填充数据 当新的过滤列表时似
  • 如何从该 Voronoi 图数据中获取单元格字典?

    使用找到的voronoi delaunay图生成库在这个节目中 http sourceforge net projects mapmanager 这是基于 财富 最初的实施他的算法 http en wikipedia org wiki Fo

随机推荐

  • Python+Selenium安装及环境配置

    转自 https www cnblogs com sandysun p 7838113 html 一 Python安装 Window系统下 python的安装很简单 访问python org download 下载最新版本 安装过程与其他w
  • 摄像头网络模组的使用

    摄像头和网络模组尾线如上图所示 利用上面两个模组 打算自己做一个简单的网络摄像头 在上面的模组网站上找到对应模组的接口定义资料 因为我们要自己将对应的网线接口等接好 本模组的接口如下 具体的该模组的接线如上所示 该网络模组尾线总共有 根 根
  • B07_NumPy 高级索引(整数数组索引,布尔索引,花式索引)

    NumPy高级索引 NumPy 比一般的 Python 序列提供更多的索引方式 除了之前看到的用整数和切片的索引外 数组可以由整数数组索引 布尔索引及花式索引 整数数组索引 以下实例获取数组中 0 0 1 1 和 2 0 位置处的元素 实例
  • 文储研习社第17期

    文储研习社是文储区块链技术人员自发组织的学习交流社区 旨在于追踪区块链时下最新热点 解码热点蕴含的未知领域 享受思想交流的碰撞 欢迎志同道合的小伙伴加入我们 共同学习与成长 第17期 为了提高考证通过率 不小心搭了条链 作者 Bingo 你
  • java springboot 8080端口号冲突时 修改当前项目端口号

    背景 springboot 项目启动时报错 Web server failed to start Port 8080 was already in use 报错原因 端口被占用 解决方案 修改项目application properties
  • SpringCloud整合Eureka出现“Error creating bean with name ‘configurationPropertiesBeans‘ defined in......“

    笔者在实现SpringCloud整合Eureka注册中心时出现如下报错 org springframework beans factory BeanCreationException Error creating bean with nam
  • C++ 类:类相关的非成员函数、构造函数

    前提 仍有 Sales data 类的代码 struct Sales data std string isbn const return bookNo 返回 isbn 编号 Sales data combine const Sales da
  • cpplint在VS Code中的安装及使用

    目录 前言 Python环境的配置 在VS Code中安装相应插件 补充 如何将VS Code默认的格式化风格改为Google风格 相关链接 前言 cpplint是一款Google的代码检查工具 确定一种编码风格对于我们有非常大的帮助 也可
  • Qt视频播放器[QMediaPlayer+QVideowidget]

    目录 参考 一 安装K Lite 解码器 二 Qt代码结构 VideoPlayer pro main cpp videoplayer h 播放器 videoplayer cpp 播放器 videoplayer ui 播放器 playersl
  • Python爬虫抓取经过JS加密的API数据的实现步骤

    随着互联网的快速发展 越来越多的网站和应用程序提供了API接口 方便开发者获取数据 然而 为了保护数据的安全性和防止漏洞 一些API接口采用了JS加密技术这种加密技术使得数据在传输过程中更加安全 但也给爬虫开发带来了一定的难度 在面对经过J
  • 常用集成运放电路合集(简洁易懂,附Multisim仿真文件)

    电赛初试培训整理的常用的集成运放电路集合 尽可能地追求全面 本文省略繁琐的推导过程 直接给出电路及其功能 以便读者使用时进行查阅 由于每个电路的介绍可能相对简略 实际使用或学习时可在站内查阅资料 网上资料丰富 在此不再赘述 本文目的是提供一
  • 树莓派体验3 - SSH登录树莓派

    如果没有HDMI转接线 显示器 USB转TTL串口线 那么可以通过网络SSH远程登录的方式访问树莓派 无显示器使用SSH访问 开启SSH服务 首先 通过镜像版本号确认一下SSH是否默认开启 树莓派官网的release note中说明 201
  • SQL的使用规范

    高程序运行效率 优化应用程序 在SP编写过程中应该注意以下几点 a SQL的使用规范 i 尽量避免大事务操作 慎用holdlock子句 提高系统并发能力 ii 尽量避免反复访问同一张或几张表 尤其是数据量较大的表 可以考虑先根据条件提取数据
  • 小程序主体为个人的教育类小程序备案——教育APP备案问题

    今天微信小程序后台发了通知 看了一下 我的小程序选择了 教育分类 思考了一下 虽然我选择了 教育 但是我的小程序是属于字典工具类的 与教育备案没什么关联 解决的办法 删除教育分类 老老实实备案 我选择了 因为我想了解下个人主体的小程序能不能
  • VS2019下的GAMES101作业环境配置

    序 很久很久以前 好像看过这个 GAMES101 现代计算机图形学入门 闫令琪 哔哩哔哩 bilibili 里面好像还有一个实验 当时只是看了看视频里的热闹 并没有写实验 现在想想 还是写一写的好 万一以后用上了呢 虽然是个24K纯小白 估
  • 解决Logback日志不会每天生成新文件的问题

    logback配置文件 问题现象 上图是最初的logback的配置 线上发现经常不会按日生成日志文件 而是一个日志越来越大 只有在项目重启之后才会生成当天的日志文件 原因分析 该配置使用了基于时间的滚动切割策略 TimeBasedRolli
  • 离散数学模拟微信红包算法升级版

    可以自定义红包总金额 总包数 每包最小金额
  • 关于springboot的序列化和反序列化问题

    在springboot中有时候需要将Datatime的格式进行格式化 有时候Long型的数据超过16位传值到前端js中会丢失精度 解决这个问题需要将Long型先转为String类型在传值到前端 所以可以编写实现类继承ObjectMapper
  • PicoNeo3开发VR——小白教程

    不断更新中 欢迎大佬们来指导 纠错 导入PicoVRSDK 1 新创一个Unity工程 Unity版本最好选择2019 4以上版本 以及需配置好安卓环境 然后导入官方picoVRSDK 2 渲染设置 Graphics APIs暂不支持Vul
  • DirectShow系列讲座之二——Filter原理

    在上一讲中 笔者介绍了DirectShow的总体系统框架 从这一讲开始 我们要从程序员的角度 进一步深入探讨一下DirectShow的应用以及Filter的开发 在这之前 笔者首先要特别提一下微软提供的一个Filter测试工具 GraphE