简介:DSPack Delphi10.2 是一套面向 Delphi 10.2 开发者的多媒体组件包,专为 Windows 10 下高清摄像头实时监控与视频流处理而设计,支持视频流捕获、帧率控制、分辨率调整等常用功能,可解决原生驱动在 Win10 上的兼容性问题,适合构建视频预览、图像采集或监控程序的桌面开发者。压缩包共 82 个文件,约 6.64MB,主要包含 Pascal 源码(.pas)、编译单元(.dcu)、窗体设计(.dfm)、包工程(.dpk/.dproj)与帮助文档(.chm),覆盖源码编译到示例运行的完整链路。目前已有 533 人学习下载,作为第三方组件包在 Delphi 社区中具有一定参考价值。资源内附带作者自制的 Demo,演示高清摄像头实时监控预览的完整流程,包括初始化、预览、帧处理等关键步骤,并配有可运行的示例工程。同时提供 DSPack 源代码与设计期编辑器,便于修改组件行为或深入理解 DirectShow 封装细节,对希望绕开 Win10 驱动兼容性问题的开发者是一份可直接落地的参考。 最近在 Delphi 10.2 环境里重新折腾了一遍 DSPack,这个老牌 DirectShow 封装库确实有点年久失修,但用好了依然是 Delphi 多媒体开发的杀手锏。如果你正在做音视频播放、摄像头采集、RTSP 拉流这类桌面应用,又不想改用其他语言重写,这篇文章会把我的实际操作过程和踩坑记录完整捋一遍,从环境配置到代码骨架再到疑难杂症,一次性给你讲透。

1. 为什么 2025 年还在用 Delphi 10.2 折腾 DSPack

先说点背景。DSPack 是基于 DirectShow 的 Delphi 封装组件包,最早在 SourceForge 上维护,最后一个比较完整的版本是 2.3.7,发布时间早得离谱。它解决的问题很直接:Delphi 本身没有官方多媒体框架,想调用 DirectShow 的 Filter Graph、Sample Grabber、视频渲染这些 COM 接口,手写声明代码会写到怀疑人生。DSPack 把这些全部封装成可视组件,拖拽几下去,设置几个属性,一个能播视频、能采集摄像头、能录制音频的软件雏形就出来了。

很多老项目到现在还跑在 Delphi 10.2 上,不是不想升级 IDE,是业务代码和历史包袱太重。这种组合下的音视频功能,十有八九都靠 DSPack 撑着。另外,Delphi 10.2 是 Rad Studio 10.2 Tokyo 这个版本,对老组件的兼容性其实比后来的 10.3、10.4 还好一点,至少没有把 Winapi 前缀问题搞得更复杂。所以明确指出:在 Delphi 10.2 下把 DSPack 调通,短期内仍然有很强的现实意义。

这套组合适合三类人:一是手头维护着老项目、需要在新环境里重新编译部署的工程师,二是想用 Delphi 快速做一个带音视频能力的工具软件、不想投入太多学习成本的同学,三是单纯想深入理解 DirectShow 工作原理、拿源码当教材的爱好者。下面所有内容我都按“真实可用”标准来写,不是那种复制粘贴官方文档的敷衍玩意。

2. 环境配置与安装细节

2.1 源码获取与目录规划

先去 SourceForge 把 DSPack 2.3.7 的源码包下载下来,压缩包体积不大,解压后能看到 Source、Packages、Demos 这几个核心目录,结构很清晰。这里我建议你把它解压到一个没有中文、没有空格的路径下,比如 D:\Lib\DSPack,原因后面讲。

Delphi 10.2 自带官方的第三方组件安装方式,用 IDE 的“打开包”功能即可。不过 DSPack 太老,直接用包文件打开会踩不少坑。正确的路径是:先打开 Packages\Delphi10\DSPack10.dpk,Delphi 10.2 的包编译器会自动尝试加载;如果报错说不认识某些单元,多半是年代问题,需要稍微做点兼容处理,这个下面会详细讲。

2.2 编译前的目录路径配置

在编译 DSPack 包之前,有一件事必须提前做:在 IDE 的 Tools > Options > Library 里,把 D:\Lib\DSPack\Source 添加到 Library path,而且要把 Delphi 默认的搜索路径顺序改一下,确保 DSPack 的 Source 目录排在最前面。否则编译时可能找到 Delphi 自带的同名单元,导致一堆命名空间冲突。

然后才是真正打开和编译 DSPack10.dpk。第一次编译,如果你是默认安装的 Delphi 10.2,大概率会看到找不到 basectp、ds_ddraw、ds_intf 之类单元的报错。不用慌,这不是代码坏了,是 Source 目录没有被正确搜到,回到上一步重新检查路径,或者把 Source 里面各个子目录都加进去,编译才能继续走下去。

编译时建议选择 “Build” 而不是 “Compile”,让编译器把整个依赖链老老实实全部重建一遍。包编译成功后,IDE 会提示是否安装到组件面板,选 Yes,工具栏上就会出现 DSPack 的一个新组件页,拖拽组件就能用了。

2.3 老包在新 IDE 里的兼容性修补

DSPack 当初是基于老版本 Delphi 写的,里面用了不少已经被新版本弃用的 API 或旧语法。我在 Delphi 10.2 上编译时,主要遇到过两个典型问题。

第一个是 PChar 互转问题,代码里直接用 PChar 字符串字面量做函数参数,新版本编译器会警告甚至报错。解决方式比较直接:把这些地方改成 StrPCopy 辅助函数,或者用 PChar(string) 做一次显式转换,就能解锁。

第二个是部分 Windows API 结构体的大小不匹配问题,这通常在播放视频或枚举设备时才会触发,编译期反而不报。这里的经验是,遇到结构体相关报错先别急着改代码,先查一下这个结构是不是在较新的 Windows SDK 里改变了定义,很多情况下可以在代码里用 Delph 的{$EXCESSPRECISION ON} 或者直接手写记录类型来绕过。

补丁打完之后,包就能在 Delphi 10.2 环境下正常安装使用了。安装成功的标准很简单:新建一个 VCL 项目,在组件面板里能看到 DSPack 页,并能拖出 TFilterGraph、TVideoWindow、TSampleGrabber 这些组件,到这一步环境就算通了。

3. 核心功能开发速成:播放、采集、录制

DSPack 全套组件有一堆,但日常真正高频使用的核心组件非常集中,我把它们列成一个对照表,开发时心里有个底。

组件 作用 典型场景
TFilterGraph 整个 DirectShow 管线的容器,管理各个 Filter 的连接与调度 所有视频音频应用都绕不开它
TVideoWindow 视频渲染窗口,把画面输出到指定控件上 播放器主界面、摄像头预览区域
TSampleGrabber 抓取经过它的媒体样本数据,拿到原始帧做处理 帧截图、视频分析、人脸识别输入
TFilter 直接封装单个 DirectShow Filter 网络流、特殊解码器接入
TAudioCapture 音频采集封装 录音、语音识别输入

3.1 快速实现一个视频播放器

可运行的骨架代码,其实就是把一个文件路径交给 FilterGraph,让它自动构建播放管线。你要是第一次接触 DirectShow 这套概念,把它想象成一条流水线:Source 负责读文件,Demux 负责拆流,Decoder 负责解码,Renderer 负责把画面画出来,DSPack 的 FilterGraph 就是那个帮你自动焊接流水线的机器人。

播放这块的代码相当简洁,核心逻辑如下:

procedure TForm1.OpenAndPlay(AFileName: string);
begin
  FilterGraph1.Active := False;
  FilterGraph1.ClearGraph;
  VideoWindow1.FilterGraph := FilterGraph1;
  // 让 FilterGraph 自动选择解码器并构建管线
  FilterGraph1.RenderFile(AFileName, nil);
  FilterGraph1.Active := True;
  FilterGraph1.Play;
end;

有一点必须写清楚:RenderFile 是同步调用,遇到解码器缺失或文件损坏时,它可能长时间卡住或者直接抛异常,所以建议在调用之前用 FileExists 检查文件,并把调用包在 try/except 里面。播放完成后,要释放管线资源,直接把 FilterGraph 的 Active 置为 False 即可。

如果是要做一个可暂停、可停止、可跳转的完整播放器,一般在这三个方法上做文章:

// 暂停
FilterGraph1.Pause;
// 继续
FilterGraph1.Play;
// 停止并复位
FilterGraph1.Stop;
MediaControl1.StopWhenReady;

跳转播放位置这块别偷懒,必须执行一次 Stop + SetCurrentPosition + Play 的组合操作,一条路子设置位置后再直接 Play 在某些解码器上会失效,这是我在实际项目里试出来的结论。

3.2 摄像头画面采集与预览

采集摄像头在 DSPack 里属于另一个套路。核心是用 FilterGraph 把视频采集设备连接到 SampleGrabber 上,再把 SampleGrabber 的输出接到 VideoWindow,这样画面能预览,数据也能在自己的回调里拿到。

设备和 Filter 的连接,可以用系统设备枚举器来做。DSPack 没有提供可视化组件来枚举设备,但提供了一个关键函数,叫 CreateFilterByCategory 之类,传入设备类别 GUID 就能拿到一个可用的 Filter 实例。常见的设备类别有 CLSID_VideoInputDeviceCategory(视频采集)、CLSID_AudioInputDeviceCategory(音频输入)。

var
  DeviceFilter: IBaseFilter;
begin
  // 拿到第一个视频采集设备
  DeviceFilter := CreateFilterByCategory(CLSID_VideoInputDeviceCategory, 0);
  // 把设备 Filter 加入 Graph
  FilterGraph1.AddFilter(DeviceFilter, 'VideoCapture');
  // 设置输出
  SampleGrabber1.FilterGraph := FilterGraph1;
  VideoWindow1.FilterGraph := FilterGraph1;
  // 预览渲染
  FilterGraph1.Active := True;
  FilterGraph1.Play;
end;

摄像头没图像或者画面是黑色的,十有八九是采集格式没设置对,要么是设备被别的进程占用,要么是 SampleGrabber 的媒体类型没有配置成 RGB 格式,建议显式调用 SampleGrabber.SetMediaType 指定格式,比如 MEDIATYPE_Video 和 VIDEOINFOHEADER 中的 RGB24。

3.3 抓帧和录制音视频

SampleGrabber 的用法是理解 DSPack 数据通路的关键。这个组件有一个 OnBuffer 事件,一旦管线跑起来,每一帧数据都会经过这里。抓帧的逻辑就是在这个事件里把 buffer 里的数据拷贝出来,再封装成 Bitmap。

procedure TForm1.SampleGrabber1Buffer(Sender: TObject;
  SampleTime: Double; pBuffer: Pointer; BufferLen: Integer);
var
  BMP: TBitmap;
begin
  BMP := TBitmap.Create;
  try
    BMP.Width := VideoWidth;
    BMP.Height := VideoHeight;
    BMP.PixelFormat := pf24bit;
    // 直接把 DirectShow 给你的视频帧数据拷贝到位图缓冲区
    Move(pBuffer^, BMP.ScanLine[0]^, BufferLen);
    Image1.Picture.Bitmap.Assign(BMP);
  finally
    BMP.Free;
  end;
end;

这里有个大坑你要记住:OnBuffer 事件是运行在 DirectShow 的工作线程里的,不是你 UI 线程。你要是直接在事件里操作 VCL 控件,轻则有几率刷新闪烁,重则直接内存访问冲突退出进程。正确的做法是,事件里只负责把数据拷贝到一个线程安全的缓冲区,然后在主窗体里用 TTimer 或者 TThread.Synchronize 去取数据并刷新显示。

录制功能通常需要把 SampleGrabber 接到编码器再接到文件写入器,过程会更麻烦,通常的做法是引入额外的 Filter,比如开源的 x264 编码器和 AVI Mux。我建议在前几个版本里不要上无损采集,给 CPU 和磁盘带来的压力都很直接,先跑通编码管线再考虑画质问题。

4. 高频事故现场与排查手册

4.1 组件装上了但一运行就报地址冲突

这个在 DSPack 开发里出现频率极高。主要原因是 FilterGraph 的 Active 生命周期管理不当:正常流程是初始化时需要激活,释放时需要把 Active 设为 False,反复进页面或者重复打开关闭窗口时,如果你忘了先反初始化,COM 对象会被重复创建和释放,导致各种奇奇怪怪的地址异常。

我的建议是做一个统一的资源释放函数:

procedure TForm1.ReleaseGraph;
begin
  if Assigned(FilterGraph1) and FilterGraph1.Active then
  begin
    FilterGraph1.Stop;
    FilterGraph1.Active := False;
    FilterGraph1.ClearGraph;
  end;
end;

在每次开始播放前调用一次,每次窗体销毁时再调用一次,可以让绝大部分随机崩溃直接消失。

4.2 视频窗口一片黑或者闪烁

视频窗口黑屏有几个常见原因。先说滤波器渲染器方面:DSPack 默认的视频渲染是标准 Video Renderer,老机器上没问题,但 Win7 以上系统建议切换成 EVR 或者 VMR9,不然可能被系统的硬件加速策略冲突,表现为黑屏。

另一个常见原因是颜色格式不一致。摄像头出的是 YUY2,SampleGrabber 配置却是 RGB24,中间少了转换环节,画面就会卡在黑色或花屏。解决方式是:在连接管线之前,给 SampleGrabber 设置明确的媒体类型,并依赖 DSPack 内置的色彩空间转换 Filter 来自动适配。

第三方解码器兼容问题:比如你要播放 MP4、MKV 这类封装格式,系统自带的解码器很有限,建议装 LAV Filters 或者 K-Lite Codec Pack。DSPack 的 RenderFile 会自动找到注册在系统里的解码器,没有外部解码器它自己也是巧妇难为无米之炊。

4.3 32 位 vs 64 位问题

DSPack 底层绝大多数代码是围绕 32 位 COM 接口来写的,官方包的源代码基本没有为 64 位专门修过。如果你在 Delphi 10.2 里新建项目选了 64 位 Windows 目标平台,编译可能过,但运行时钩子函数和使用指针的地方大概率出问题。

我的建议是:用 DSPack 做重活的项目,老老实实以 32 位为目标平台。这在 2025 年听起来反而有点“老派”,但稳定性第一,没有必要用 64 位去挑战自己。

如果业务确实需要 64 位,那就得换思路了:不直接调用 DSPack 组件,而是用 DSPack 的源码做参考,自己封装 DirectShow 接口。这是一个非常非常大的工作量,我有同事做过,折腾了一周才稳定,只为了一个摄像头功能,性价比实在不高,不如考虑用中立一点的多媒体框架。

4.4 Demo 项目编译不过

源码包里的 Demos 文件夹有很多现成例子,但它默认引用的路径是相对路径,解压到不同盘符时会失效。看到 Project 找不到某个文件,别急着改代码,先看 Project 属性里的搜索路径是不是指向了 D:\Lib\DSPack\Demos 下的某些共享文件夹。

还有一个常见错误是找不到 DsPack_DS.inc 之类的包含文件,这是因为老包很多时候需要用后缀为 .inc 的公共头文件来传递平台和版本定义。确保 IDE 的“包含文件搜索路径”里也加上了 Source 目录,否则 Demo 工程里面某些 pas 文件会解析失败。

5. 常见问题速查表

问题现象 可能原因 直接解决方案
安装 DSPack 包时出现 basectp.dcu not found Source 目录未加入 Library 搜索路径 在 IDE Library Path 中添加 DSPack 的 Source 根目录
64 位编译通过但运行时崩溃 DSPack 对 64 位支持不完善 切回 32 位目标平台,或者自行封装 COM 接口
视频播放黑屏但有声音 渲染器与系统 GPU 加速不兼容 在 FilterGraph 上设置 VMR9/EVR 渲染器
摄像头画面花屏 媒体类型不匹配,多为 YUY2 和 RGB 混用 显式设置 SampleGrabber 媒体类型为 RGB24
抓帧 OnBuffer 里操作 UI 崩溃 DirectShow 回调线程与 UI 线程冲突 回调中只拷贝数据,通过 TTimer/同步方式更新控件
中文路径下 Demo 打不开 老组件对 Unicode 支持弱 项目路径和源码路径都不要用中文、空格
找不到 MP4 解码器 系统缺少第三方解码组件 安装 LAV Filters 或同类解码器
循环播放时内存异常 FilterGraph 的 Active 未正确释放 每次新播放前 Stop + Active=False + ClearGraph

这个问题清单是根据我长期折腾整理出来的,已经覆盖了绝大多数初上手者的报错场景。

6. 几个值得记住的实操经验

最后再分享一点我自己摸索下来最有价值的东西,这些东西没有写在 DSPack 文档里,是实打实跑出来的经验。

一是用 DSPack 做应用时,不要图省事把整个 FilterGraph 都放在主窗体上。我的习惯是把所有多媒体逻辑封装在一个独立类里,主界面通过消息或事件和它通信。这样一旦图形管线崩了,主窗体还能响应关窗操作,不会出现“无响应”的尴尬。

二是 SampleGrabber 拿到的数据的时间戳,别轻易用。DirectShow 时间戳在某些解码器上可能是错乱的,尤其是网络流或者转码过的本地文件,你在负责展示同步时,用自己的系统时钟反而更稳。

三是老包不代表没有价值。DSPack 全部用 Delphi 写,代码风格老但是非常清晰,你想理解 DirectShow 的 Filter Graph 到底是怎么运转的,直接看它的 pas 源文件,比看微软官方文档更容易懂。这也是我在多年后依然愿意维护一套老 Delphi 环境的主要原因,它背后基本就是 Windows 媒体处理的祖师爷级别的思路。

如果你也已经把 DSPack 在 Delphi 10.2 上跑通了,建议你后续可以往两个方向扩展:一是把采集到的视频帧接入到图像识别流程里,二是尝试用 DSPack 的音频采集做实时频谱可视化。这两个方向都不需要太重的新框架,在现有代码上做扩展非常舒服,也最能体现出 DSPack 的直接抓数据能力。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

邀请您加入社区

更多推荐