热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

DirectShowFilter开发指南

本文总结了DirectShowFilter的开发经验,重点介绍了SourceFilter、In-PlaceTransformFilter和RenderFilter的实现方法。通过使用DirectShow提供的类,可以简化Filter的开发过程。

本文总结了 DirectShow Filter 的开发经验,重点介绍了 Source Filter、In-Place Transform Filter 和 Render Filter 的实现方法。通过使用 DirectShow 提供的类,可以简化 Filter 的开发过程。

在 DirectShow 中,Filter 主要分为三类:Source Filter、Transform Filter 和 Render Filter。这三类 Filter 的主要区别在于它们包含的 Pin 类型。Source Filter 至少有一个输出 Pin 而没有输入 Pin;Transform Filter 至少有一个输入 Pin 和一个输出 Pin;Render Filter 至少有一个输入 Pin。Pin 是一种 COM 组件,负责连接两个 Filter 并传输数据。如下图所示:

两个 Pin 之间的连接过程实际上是一个媒体类型协商过程,包括以下几个步骤:

  1. 调用输出 Pin 上的 Connect 方法。
  2. 调用输入 Pin 上的 ReceiveConnection 方法。
  3. 如果上述两个方法都成功,则连接成功。
  4. 在输出 Pin 上调用 CompleteConnect 方法,进行内存分配和管理。

完成上述步骤后,两个 Filter 之间就可以进行数据传输了。数据传输的具体形式是通过 Sample 实现的。Sample 是数据的载体,由 Allocator 创建和管理。数据传输时,输出 Pin 会调用 IMemAllocator::GetBuffer 方法获取一个 Sample,然后使用 IMediaSample::GetPointer 获取 Sample 的内存地址,填充数据并传递给下一个 Filter 的输入 Pin。

数据传输方式主要有两种:推模式(Push mode)和拉模式(Pull mode)。

推模式

推模式主要用于实时源,如摄像头图像采集。与之连接的下级 Filter 需要实现 IMemInputPin 接口。在数据传输时,Source Filter 完成数据读取后,会主动调用下级 Filter 的 IMemInputPin::Receive 或 IMemInputPin::ReceiveMultiple 方法传递数据。

拉模式

拉模式主要用于文件源,如视频文件的回放。要使用拉模式,需要实现 IAsyncReader 接口。数据传输时间与推模式相反,即在需要数据时,由上级 Filter 的输入 Pin 主动请求数据,调用 IAsyncReader 接口上的方法。IAsyncReader 数据处理方法包括:Request(异步)、SyncReadAligned(同步对齐)和 SyncRead(同步)。

推模式和拉模式只是数据传输的两种方式,开发过程中可以根据实际需求选择。通常推荐在实时源时使用推模式,在文件源时使用拉模式,以减少不必要的工作。

当一个 Source Filter 结束发送数据流时,它会调用连接的 Filter 的输入 Pin 的 IPin::EndOfStream 方法,然后下游的 Filter 依次通知与之相连的 Filter。当 EndOfStream 方法调用到 Render Filter 时,最后一个 Filter 会给 Filter 图表管理器发送一个 EC_COMPLETE 事件通知。如果 Render Filter 有多个输入 Pin,当所有输入 Pin 都接收到 EndOfStream 通知时,它才会给 Filter 图表管理器发送 EC_COMPLETE 事件通知。

Source Filter 实现

Source Filter 是一个提供数据的 Filter,数据可以是本地音视频流、图片数据、实时采集数据等。这里分别给出推模式和拉模式的例子。

推模式示例(BMP 图片)

尽管推模式主要用于实时源,但这里给出一个用推模式推送文件源的例子。这个 Filter 的功能是主动向下一个 Filter 推送图片数据,最终由系统的 Render Filter 显示。

  1. Filter 注册。创建至少一个 GUID,并在 CPP 文件中写入相关代码。
  2. 选择一个基类,这里选择 CSource。Source Filter 包含一个或多个输出 Pin(这里为 1 个)。这个输出 Pin 派生于 CSourceStream(这里为 CFileStream)。
  3. 实现必要的方法,包括 CSourceStream::GetMediaType、CSourceStream::CheckMediaType、CBaseOutputPin::DecideBufferSize 和 CSourceStream::FillBuffer。
  4. 在 SourceFilter 类中实现 CreateInstance 方法。
  5. 在 SourceFilter 类中定义一个 CSourceStream 的指针成员变量 m_pPin,并在构造函数中创建输出 Pin 对象。

接下来,具体实现 CFileStream 类:

  1. 在 CFileStream 的头文件中添加成员变量。
  2. 在 CFileStream 的构造函数中初始化成员变量。
  3. 实现 CFileStream::GetMediaType 方法,设置推送数据的媒体类型。
  4. 实现 CFileStream::DecideBufferSize 方法,决定 Buffer 的大小。
  5. 实现 CFileStream::FillBuffer 方法,为 Buffer 填充数据。

至此,一个推模式的 Source Filter 就完成了。总体来看,实现这个 Filter 只需重写几个关键方法:CSourceStream::GetMediaType、CBaseOutputPin::DecideBufferSize 和 CSourceStream::FillBuffer。

拉模式示例(视频播放)

拉模式的 Source Filter 比推模式的 Source Filter 复杂一些,但通过基类来实现也并不困难。在拉模式中,推荐使用 CBaseFilter 和 CBasePin,且必须实现 IAsyncReader 接口。

  • 实现 CBaseFilter 的步骤包括:
    1. 从 CBaseFilter 派生一个新类。
    2. 为新类添加一个继承自 CBasePin 的 Pin 成员变量。
    3. 重写 CBaseFilter::GetPin 方法,返回 Filter 上的 Pin。
    4. 重写 CBaseFilter::GetPinCount 方法,返回 Filter 上的 Pin 数量。
  • 实现 CBasePin 的步骤包括:
    1. 重写 CBasePin::CheckMediaType 方法,检查媒体类型。
    2. 重写 CBasePin::GetMediaType 方法,获取媒体类型。
    3. 重写 IPin::BeginFlush 和 IPin::EndFlush 方法,用于清除数据。
  • 重写 IAsyncReader 的所有方法,包括:
    1. IAsyncReader::BeginFlush 和 IAsyncReader::EndFlush,用于清除数据。
    2. IAsyncReader::Length,返回数据流的总长度和可用长度。
    3. IAsyncReader::RequestAllocator,用于 Pin 连接时的内存分配和管理。
    4. IAsyncReader::Request,异步请求数据。
    5. IAsyncReader::SyncReadAligned,同步对齐请求数据。
    6. IAsyncReader::SyncRead,同步请求数据。
    7. IAsyncReader::WaitForNext,等待请求的执行完成。

通过上述步骤,可以实现一个拉模式的 Source Filter,用于视频文件的回放。


推荐阅读
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 计算机网络复习:第五章 网络层控制平面
    本文探讨了网络层的控制平面,包括转发和路由选择的基本原理。转发在数据平面上实现,通过配置路由器中的转发表完成;而路由选择则在控制平面上进行,涉及路由器中路由表的配置与更新。此外,文章还介绍了ICMP协议、两种控制平面的实现方法、路由选择算法及其分类等内容。 ... [详细]
  • 本文介绍了如何利用JavaScript或jQuery来判断网页中的文本框是否处于焦点状态,以及如何检测鼠标是否悬停在指定的HTML元素上。 ... [详细]
  • This guide provides a comprehensive step-by-step approach to successfully installing the MongoDB PHP driver on XAMPP for macOS, ensuring a smooth and efficient setup process. ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
author-avatar
手机用户2602931635
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有