热门标签 | 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,用于视频文件的回放。


推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 本文详细介绍了Java中的输入输出(IO)流,包括其基本概念、分类及应用。IO流是用于在程序和外部资源之间传输数据的一套API。根据数据流动的方向,可以分为输入流(从外部流向程序)和输出流(从程序流向外部)。此外,还涵盖了字节流和字符流的区别及其具体实现。 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 本文深入探讨了HTTP请求和响应对象的使用,详细介绍了如何通过响应对象向客户端发送数据、处理中文乱码问题以及常见的HTTP状态码。此外,还涵盖了文件下载、请求重定向、请求转发等高级功能。 ... [详细]
  • 资源推荐 | TensorFlow官方中文教程助力英语非母语者学习
    来源:机器之心。本文详细介绍了TensorFlow官方提供的中文版教程和指南,帮助开发者更好地理解和应用这一强大的开源机器学习平台。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • 不确定性|放入_华为机试题 HJ9提取不重复的整数
    不确定性|放入_华为机试题 HJ9提取不重复的整数 ... [详细]
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社区 版权所有