简介:DSPACK 2.3.4 for Delphi 5/6/7 是一套面向老版本 Delphi 开发者的 DirectShow 与 DirectX 封装库,主要解决音视频捕获、播放、录制以及摄像头控制等多媒体开发难题。压缩包共 277 个文件,大小仅 1.78MB,其中以 pas 源文件、dpr 工程、dfm 窗体、dpk 包文件为主,也包含 lib 静态库、bat 脚本、h 头文件等,分类清晰,便于在 Delphi 5/6/7 中直接加载或修改。资源覆盖 DirectShow 过滤器图操作、DirectSound 音频混音、AVI/WMV/MP3 等格式读写、摄像头分辨率与帧率调节等核心功能,并附带示例工程和帮助文档,能让开发者直观理解视频聊天、监控采集、简单播放器等应用的搭建流程。目前已有 498 人学习下载,对于仍在使用经典 Delphi 环境并希望引入多媒体能力的开发者来说,是一份轻量实用、参考价值较高的工具库。
1. 项目概述:DSPACK 2.3.4 到底是什么
如果你混过 Delphi 的多媒体开发圈子,应该对 DSPACK 不陌生。这个开源组件库从 2001 年左右开始活跃,专门把微软 DirectShow 那套庞大的多媒体框架封装成 Delphi 能直接调用的 VCL 组件。简单说,有了它,你可以在 Delphi 5、6、7 里像拖个 Button 一样拖一个 TFilterGraph 到窗体上,然后几行代码就能实现摄像头采集、视频播放、音频处理这些功能。
DSPACK 2.3.4 是这套组件库在 Delphi 5/6/7 时代的一个经典稳定版本。我知道今天还有不少人在纠结——都 2024 年了,还有人用 Delphi 7 吗?实际情况是,很多工业控制、医疗设备、老系统维护项目里,Delphi 7 依然在跑,而且跑得稳。尤其是一些需要对接 USB 摄像头、采集卡、音视频流的项目,DSPACK 几乎是唯一一个能靠得住的开源选择。
这篇博文我打算围绕 DSPACK 2.3.4 在 Delphi 5/6/7 下的实际使用,把环境配置、视频采集、播放、滤镜处理这几个核心场景讲透,再把当年踩过的坑一并列出来。适合三类人看:一是刚接手老项目需要补课的新手,二是想在 Delphi 里做音视频功能的开发者,三是还在维护 Delphi 7 代码的老兵。
2. 环境准备与安装配置
2.1 下载与目录结构解读
DSPACK 2.3.4 的发布包是一个压缩文件,解压后目录结构大致如下:
DSPACK_2.3.4/ ├───packages/ │ ├───D5/ │ ├───D6/ │ └───D7/ ├───source/ │ ├───DirectShow9/ │ ├───DSPack/ │ └───BaseClass/ └───demos/packages目录下按 Delphi 版本分了三个子目录,里面是 .dpk 包文件,直接用对应版本的 Delphi 打开编译即可。source目录是核心源码,其中DirectShow9是 DirectShow 接口的 Pascal 翻译版本,DSPack是封装好的组件源码,BaseClass是 C++ 基类的 Pascal 移植。
这里有一个关键点:DSPACK 2.3.4 依赖 DirectX 9 的运行时和开发头文件。在 Windows 2000/XP 时代,DirectX 9 几乎是标配,但如果你在 Windows 7 以上的系统里装,需要确保系统里有 DirectX 9 的运行库。Windows 10/11 自带 DirectX 12,向下兼容到 DirectX 9,所以一般没问题。但编译器那头需要能读到 DirectX 的 Pascal 头文件——DSPACK 源码里自带了一套翻译好的头文件,不需要额外装 DirectX SDK,这点比很多老库要省心。
2.2 Delphi 7 环境下的安装步骤
我自己主要在 Delphi 7 下用,安装顺序是固定的,照着走不会出问题:
第一步,打开 Delphi 7,在File > Open里定位到packages/D7/目录,先打开dspack_d7.dpk。
第二步,右键 Project Manager 里的包名,选择Compile。编译过程大概十几秒,如果报错,九成是源码路径没加对——需要在Tools > Environment Options > Library > Library Path里把source/DirectShow9、source/DSPack、source/BaseClass这三个目录都加进去。
第三步,编译通过后,在包管理器里点Install。这时组件面板会多出一页叫DSPack,里面有 TFilterGraph、TSampleGrabber、TVideoWindow、TAudioCapture 等十几个组件。
第四步,如果你需要用 TDSVideoCaptureProperties 这类属性编辑器,还得把source/DSPack目录下的 .dfm 文件也纳入搜索路径,不然 IDE 会提示找不到资源文件。
我在实测中遇到过一个问题:某些精简版 Delphi 7 缺少adstunits.pas这个单元,编译 DPK 时直接报“File not found”。解决方法是源码包里搜索这个文件,把它复制到lib目录下。这就是老库的典型脾气——依赖文件不全,需要手动补。
2.3 新建项目注意的搜索路径
安装完组件只是第一步,实际建项目的时候,很多新手在Project > Options > Directories/Conditionals里忘了把 DSPACK 的源码路径加进去,导致编译时提示找不到DirectShow9.pas。
我的建议是配置以下路径:
C:\DSPACK_2.3.4\source\DirectShow9 C:\DSPACK_2.3.4\source\DSPack C:\DSPACK_2.3.4\source\BaseClass同时,如果编译 64 位目标——这又是一个老库的老问题——DSPACK 2.3.4 源代码基于 32 位指针假设写的,在 Delphi XE 以上版本里编译 Win64 目标会直接报错。如果你的机器是 64 位系统,务必把项目目标平台设为 32 位(Win32)。这点我在第四节会再展开。
3. 核心功能实操详解
3.1 用 TFilterGraph 搭建视频播放通道
TFilterGraph 是 DSPACK 中最核心的组件,它的作用是管理 DirectShow 滤镜图(Filter Graph)的整个生命周期。滤镜图这个概念初学者可能要绕一下——我打个比方:一个视频播放任务就像一条流水线,源文件是原材料,分离器把原料拆成视频流和音频流,解码器把压缩流解成原始帧,渲染器把帧画到屏幕上。TFilterGraph 就是这个流水线的总调度员。
要在 Delphi 7 里实现播放视频文件,代码非常简单:
uses DSPack, DirectShow9; procedure TForm1.PlayVideo(AFileName: string); begin FilterGraph1.Active := False; FilterGraph1.ClearGraph; FilterGraph1.RenderFile(AFileName, nil); FilterGraph1.Play; end;这段代码的背后,RenderFile方法会自动检测文件类型并选择匹配的分离器和解码器,不需要你手动搭建滤镜链——这是 DSPACK 提供封装的意义。实际使用中,我发现几个细节值得注意:
第一,ClearGraph之后必须等一两帧时间再RenderFile,否则在某些显卡驱动下会出现画面撕裂;
第二,播放前建议设置FilterGraph1.VideoWindow := Panel1来指定视频渲染窗口,不然系统会弹出一个独立的播放窗,很突兀;
第三,播放结束后要手动调用FilterGraph1.Stop,否则音频设备会被占用,别的程序放不出声。
3.2 TSampleGrabber 实现视频帧捕获
如果你想做视频帧的实时处理——比如抓取画面保存成 BMP、做运动检测、传给图像识别算法——TSampleGrabber 是绕不开的组件。它可以在滤镜链的任意位置插入一个"窃听点",把经过的媒体样本复制一份给应用程序。
配置 SampleGrabber 有两种方式。第一种是直接在窗体上放一个 TSampleGrabber,然后手动连接;第二种是通过代码创建并插入滤镜图。
我推荐用代码方式,灵活度更高:
var Grabber: TSampleGrabber; MediaType: TAMMediaType; begin Grabber := TSampleGrabber.Create(Self); with Grabber do begin FilterCategory := CLSID_LegacyAmFilterCategory; FilterName := 'SampleGrabber'; end; FilterGraph1.AddFilter(Grabber, 'SampleGrabber'); // 设置抓取格式为 RGB24 FillChar(MediaType, SizeOf(TAMMediaType), 0); MediaType.majortype := MEDIATYPE_Video; MediaType.subtype := MEDIASUBTYPE_RGB24; Grabber.MediaType := MediaType; Grabber.BufferSize := 1024 * 1024; Grabber.SetOneShot(False); Grabber.SetBufferSamples(True); end;这段代码的核心是MediaType的设定。如果要抓取 24 位真彩色画面,subtype 必须是MEDIASUBTYPE_RGB24;如果你想在回调里拿到 YUV 原始数据,就要设成对应的 YUY2 或 NV12。这个选择直接影响后续图像处理的复杂度——RGB24 好处理但内存占用高,YUV 省带宽但需要做颜色空间转换。
3.3 摄像头采集与预览的实现思路
USB 摄像头采集是 DSPACK 另一大常用场景。老式 Delphi 项目里对接海康、大华等品牌采集卡,很多走的是厂商 SDK,但普适的 USB 摄像头(UVC 协议)用 DirectShow 就能通吃。
DSPACK 提供了 TVideoCapture 组件,封装了采集卡和 USB 相机的大部分操作:
procedure TForm1.StartCamera; begin VideoCapture1.FilterGraph := FilterGraph1; VideoCapture1.VideoWindow := Panel1; VideoCapture1.VideoDisplay := True; VideoCapture1.DeviceIndex := 0; // 第一个视频设备 VideoCapture1.StartPreview; end;关键点是DeviceIndex的选择。系统里可能同时存在多个摄像头或者虚拟摄像头(比如 OBS 的虚拟输出),DeviceIndex从 0 开始,对应系统设备枚举顺序。你可以通过TVideoCapture.DeviceCount属性来遍历可用设备,在界面上做成下拉框供用户选择。
另外,我强烈建议在调用StartPreview之前先检查设备是否被占用:
if VideoCapture1.DeviceCount = 0 then ShowMessage('没有检测到视频设备');因为很多摄像头驱动在同一时刻只允许一个进程独占,如果其他程序正在使用摄像头,DSPACK 会抛出EInterfaceCastException,这个异常信息比较隐晦,容易让人一时间摸不着头脑。
4. 常见问题与排查技巧实录
4.1 编译期间报错的几种典型场景
我把这几年在群里帮人排查 DSPACK 相关问题的经验整理成了几张速查表,先看编译期:
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
File not found: 'DirectShow9.dcu' | 源码路径未加入 Library Path | 在 Tools > Environment Options > Library 里添加三个源码目录 |
F2048 Bad unit format: 'xxx.dcu' | 用了其他 Delphi 版本编译出的 DCU | 删除所有 .dcu 文件,重新编译整个包 |
E2010 Incompatible types: 'PChar' and 'PAnsiChar' | 非 Unicode 库在 Unicode 版 Delphi 下的经典错误 | 尽量使用 Delphi 7 环境,或在源码里把 PChar 改成 PAnsiChar |
E1026 File not found: 'adstunits.pas' | 发布包缺文件 | 解压完整包,从其他版本目录复制缺失文件 |
第二行那个F2048是我见过最多的坑。很多人下载了源码包,先在 Delphi 6 里编了一下,后来换了 Delphi 7,没清理旧 DCU 直接编译,就会报"Bad unit format"。解决办法非常简单——把整个 source 目录下的 .dcu 文件删干净,再重新编译。
4.2 运行期典型的崩溃与黑屏
编译通过只是第一步,运行期才是真正考验 DSPACK 的地方。我遇到过黑屏、闪退、音画不同步、崩溃重启等各种问题:
| 问题现象 | 具体原因 | 处理方式 |
|---|---|---|
| 播放视频黑屏但声音正常 | 视频渲染器与显卡驱动不兼容 | 调用FilterGraph1.RenderFile(AFileName, @IID_IVMRWindowlessControl)强制使用 VMR 模式 |
| 窗口关闭后程序崩溃 | 没有停止滤镜图就释放组件 | 在 FormDestroy 里先执行FilterGraph1.Active := False; FilterGraph1.ClearGraph; |
| 采集画面卡顿严重 | 缓冲设置太小或 CPU 占用过高 | 调大Grabber.BufferSize,帧率回调里别做耗时操作 |
| 播放 RTSP 流超时 | 网络情况复杂、DirectShow 默认超时较短 | 使用链接方式FilterGraph1.RenderFile('rtsp://...', nil)前先设置FilterGraph1.DefaultSyncSource为 0 |
黑屏那个问题值得展开。老显卡和 DirectShow 的 EVR 渲染器之间经常有兼容性问题,表现就是有声音没画面。DSPACK 2.3.4 的时代还没有 EVR,用的是 VMR7/VMR9,如果你在 Windows 7 以后的系统上跑,建议干脆用RenderFile的重载形式手动指定渲染方式。
4.3 Delphi 版本跨代迁移的注意点
最后聊一个老生常谈的话题:如果把 DSPACK 2.3.4 用在更高版本的 Delphi(比如 Delphi 10.4、11、12)上,会碰见什么问题?
第一个是字符类型的变化。Delphi 2009 之后默认Char类型从 AnsiChar 变成了 WideChar,而 DSPACK 源码里的 PChar 大量用于 DirectShow 接口参数,不兼容就会报E2010 Incompatible types。可能的做法是把源码中所有 PChar 声明改为 PAnsiChar,工作量不小。
第二个是CheckDlgResult之类的老 API 被移除。这在 Delphi 2009 之后的版本会直接编译失败,需要找到替代实现或者自己补齐。
第三个是上面提到的 Win64 兼容问题。DSPACK 2.3.4 源码里的记录类型大量使用LongWord表示指针,在 Win64 下会截断地址。如果你一定要在 64 位 Delphi 里编译,需要手工把所有指针相关字段类型改成NativeUInt。
综合来看,我的建议是:如果只是维护老系统,老老实实用 Delphi 7 + DSPACK 2.3.4 的组合;如果是要在新项目里用,不如考虑别的方案,比如用 VideoLAN 的 libVLC 封装,或者用 FFmpeg+SDL 的跨平台方案,别在老库里折腾太久。
5. 实际项目中的性能调优与资源释放
5.1 帧率与分辨率的平衡策略
摄像头采集场景下,分辨率、帧率、CPU 占用三者之间需要做一个权衡。DSPACK 通过TVideoCapture.SetVideoFormat可以设置采集分辨率,但分辨率拉高之后,TSampleGrabber回调里的图像拷贝开销也会成倍增长。
举个例子:采集 1920×1080 RGB24 画面,一帧数据大小约为 1920×1080×3 ≈ 6MB,假设帧率 30fps,每秒的数据量就是 180MB。这在老机器上足以让 CPU 飙到 100%。
我的实践做法是分场景处理:
- 做预览:用 640×480 足够,降低 CPU 开销;
- 做人脸检测/条码识别:用 1280×720,检测框精度够用;
- 做视频录制:如果需要全分辨率,建议直接在滤镜图里做编码,不要在回调里逐帧处理。
回调函数里尽量只做数据拷贝和标志位设置,把耗时操作放到另一个线程去处理。DSPACK 的TSampleGrabber.OnBuffer事件是运行在 DirectShow 的工作线程里的,如果在里面做了 UI 操作,很容易引发崩溃或界面卡死。
5.2 资源释放清单
老 Delphi 程序最常见的隐患是内存泄漏和资源占用,DSPACK 程序更是如此。DirectShow 滤镜图如果释放顺序不对,轻则播放器退出后音频设备被占,重则直接蓝屏(XP 时代遇到过)。
我这里列一张释放检查清单,每次写 DSPACK 程序都在 FormDestroy 里照着写一遍:
procedure TForm1.FormDestroy(Sender: TObject); begin // 停止滤镜图 if Assigned(FilterGraph1) then begin FilterGraph1.Active := False; FilterGraph1.ClearGraph; end; // 释放采集设备 if Assigned(VideoCapture1) then VideoCapture1.StopPreview; // 释放 SampleGrabber if Assigned(Grabber) then FreeAndNil(Grabber); end;这里要特别说明:ClearGraph会尝试断开所有滤镜连接并释放引用,但如果你手动AddFilter过一些独立滤镜对象,需要先把它们从图中移除再Free,顺序反了会触发守护进程崩溃。
5.3 用 DSPACK 连接 RTSP 流媒体的经验
现在很多项目要求 Delphi 程序远程查看网络摄像头,RTSP 协议是绕不开的。DSPACK 能不能播放 RTSP 流?能,但讲究很多。
DSPACK 自带了一个 TFilterGraph 的扩展,可以加载兼容的 RTSP 滤镜,但 Windows 自带没有 RTSP 源滤镜。当年我用的方案是装一个 K-Lite Codec Pack,它内置了 LAVFilters,其中 LAV Splitter 支持 RTSP 协议,装完之后 DSPACK 就能通过RenderFile('rtsp://192.168.1.100/stream1')直接播放。
前提是机器上已经注册了 LAV Splitter 的 COM 接口。还有一种方式是手动加载滤镜:
FilterGraph1.AddFilter(CoCreateInstance(CLASS_LAVSplitter, nil, CLSCTX_INPROC_SERVER, IBaseFilter), 'LAVSplitter');用这种方式可以实现更精细的控制,比如指定 TCP/UDP 传输模式、超时时间等。但说实话,如果项目的核心需求就是拉取 RTSP 流做显示,我反而推荐用 VLC 的 ActiveX 插件或者 FFmpeg 的 DLL 对接,DSPACK 在这里的优势并不明显。
6. 写在最后的实操心得
DSPACK 2.3.4 是我在 Delphi 多媒体开发路上绕不开的一个组件库,虽然它的最后一次更新停在 2006 年左右,代码风格也带着那个年代特有的粗犷,但它的设计思路放到今天依然实用——对 DirectShow 的封装粒度恰到好处,没有过度抽象,保留了对底层滤镜链的完整控制能力。这一点比很多商业组件做得更好。
我用它做过的项目包括:银行的安防监控客户端、工厂流水线的产品视觉检测、实验室的显微图像采集系统。在这些场景里,DSPACK 的稳定性和兼容性经受住了长时间的考验。不过我也要实话实说:如果你做的是一个全新的商业产品,我可能不会推荐你选择这个老库,毕竟它不支持 64 位,维护成本摆在那里。建议先做技术预研,评估项目生命周期和运行环境再决定。
最后分享一个我个人的小技巧:DSPACK 的源码非常值得读,尤其是DSPack.pas里那几个核心组件的实现。读完它,你对 DirectShow 滤镜图的理解会比看十篇博客都深刻。这也算是老库留给后来者的一份财富吧。
本文还有配套的精品资源,点击获取