ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Delphi 12.3 集成 TVideoGrabber SDK:视频采集、录像与推流实战指南

Delphi 12.3 集成 TVideoGrabber SDK:视频采集、录像与推流实战指南

简介:本资源为Datastead.TVideoGrabber SDK V15.2.5.6全平台版,面向使用Delphi 12.3进行视频捕获与处理开发的工程师。该SDK支持从摄像头、电视卡、网络摄像机等视频源实时采集数据,并完成编码、预览、录制等操作,适合需要在Windows、macOS及Linux上构建跨平台视频应用的开发者。压缩包共1113个文件,约139.54MB,包含pas、dpr、dfm等Delphi源码与窗体文件,bpl、dcp、dcu等编译组件,以及dll、hpp、lib等跨平台库文件,另附示例工程、文档与配置文件,便于快速集成与调试。目前已有83人学习关注。借助该SDK,开发者可调用统一接口实现视频采集、格式设置、回调处理与文件保存,并参考示例项目掌握基本与高级用法,同时需留意不同平台在硬件接口、驱动及UI适配上的差异,从而高效扩展Delphi应用的视频处理能力。

1. Delphi 12.3 下 Datastead TVideoGrabber SDK 的定位与适用边界

如果你正在用 Delphi 12.3 做 Windows 桌面端的视频采集、录像或推流功能,大概率绕不开一个名字:Datastead TVideoGrabber SDK。这次标题里的 V15.2.5.6 All Platforms 版本,本质上是把一套成熟的视频采集与处理组件,打包成覆盖 Delphi、C++ Builder 以及 .NET 的多平台 SDK。它解决的核心问题很具体:让你不用从零去啃 DirectShow、Media Foundation 的底层接口,就能在窗体上拖一个控件,把摄像头、采集卡、桌面屏幕甚至 RTSP 流拉进来,做预览、录像、抓帧、叠加文字和时间戳。

我最早接触它是在一个工业检测项目里,客户要求把产线摄像头的画面实时显示在 Delphi 界面上,同时按班次自动切分录像文件。当时试过直接调 DirectShow,光是枚举设备、协商媒体类型、处理格式回退就写了两百多行,还时不时在某些 USB 采集卡上翻车。换成 TVideoGrabber 之后,核心逻辑压缩到几十行,设备兼容性也稳了很多。这就是它存在的意义:把视频采集这条链路上最容易出玄学问题的部分封装掉,留给你的是属性、事件和方法。

这个版本标注 All Platforms,需要说清楚边界。它指的是 SDK 本身提供了 Delphi VCL、FireMonkey 以及 C++ Builder 的接口单元,并不是说你的采集程序能直接编译到 Android 或 iOS 上跑摄像头采集。实际落地场景仍然是 Windows 桌面端为主,FMX 可以让你在跨平台 UI 框架里调用,但底层采集还是走 Windows 的媒体栈。所以如果你的目标是 Delphi 12.3 的 VCL 项目,这个包是对口的;如果你打算做移动端采集,需要先确认目标平台的支持情况,别看到 All Platforms 就默认全平台开箱即用。

适合谁:一是手里有 Delphi 12.3 项目、需要快速加视频功能的开发者;二是做安防、工业视觉、医疗影像、教育录播这类桌面软件,要求稳定采集和录像的团队;三是想用 C++ Builder 复用同一套 SDK 的跨语言项目。不适合谁:只需要静态图片处理、或者想用纯 Web 技术做视频的,这套东西偏重,没必要上。

2. 把 SDK 装进 Delphi 12.3:包结构、编译与第一个采集窗体

2.1 解压后先看清目录,别急着装

拿到 Datastead.TVideoGrabber.SDK.V15.2.5.6.All.Platforms.7z 之后,第一步是解压到一个路径里没有中文和空格的目录,比如D:\SDK\TVideoGrabber。路径带空格或中文,在 Delphi 的包编译和运行时 DLL 加载阶段都可能出问题,这是血泪经验。

解压后典型结构大致是这几类内容:Delphi或Delphi VCL目录放的是 VCL 组件包和单元文件;C++Builder目录放 C++ 接口;Assemblies或DotNet目录放 .NET 程序集;Redist或Runtime目录放运行时需要的 DLL;Demos或Samples目录放示例工程。不同小版本目录名可能有差异,但逻辑一致。

关键动作是找到 Delphi 对应的包文件,通常是.dpk或.dproj。用 Delphi 12.3 打开它,先别改任何东西,直接 Build。如果编译报错,大概率是搜索路径没配好,或者运行时包和设计期包混在一起了。

2.2 安装设计期包并配置搜索路径

在 Delphi 12.3 里,推荐的做法是:打开 SDK 提供的设计期包工程,右键 Install。安装成功后,工具面板上会出现 TVideoGrabber 组件。如果 Install 灰色,说明这个包被标记为运行时包,需要先找到对应的设计期包。

安装完成后,去Tools > Options > Language > Delphi > Library,在Library Path里把 SDK 的 Delphi 源码目录加进去。这样你自己的工程引用单元时不会找不到文件。同时确认Browsing Path也加上,方便调试时跳转。

提示:Delphi 12.3 的包管理对平台限定比较严格,安装时确认目标平台是 Win32 还是 Win64,两个平台要分别编译和安装对应的包,不能混用。

2.3 最小可运行的采集窗体代码

下面这段代码是我一般用来验证 SDK 是否正常工作的最小骨架。新建一个 VCL 应用,放一个 TVideoGrabber 组件、一个 TButton、一个 TPanel,然后写:

unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, VideoGrabber; type TForm1 = class(TForm) VideoGrabber1: TVideoGrabber; Panel1: TPanel; Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure VideoGrabber1Log(Sender: TObject; LogType: TLogType; Severity: TLogSeverity; const InfoMsg: string); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin // 把预览窗口挂到 Panel1 上,避免控件自己弹独立窗口 VideoGrabber1.VideoSource := vs_VideoCaptureDevice; VideoGrabber1.VideoRenderer := vr_VMR9; VideoGrabber1.PreviewWindow := Panel1.Handle; VideoGrabber1.StretchPreview := True; VideoGrabber1.OnLog := VideoGrabber1Log; end; procedure TForm1.Button1Click(Sender: TObject); begin if not VideoGrabber1.IsVideoSourceOpen then begin // 打开默认采集设备,设备索引从 0 开始 VideoGrabber1.VideoDevice := 0; VideoGrabber1.OpenVideoSource; VideoGrabber1.StartPreview; end else begin VideoGrabber1.StopPreview; VideoGrabber1.CloseVideoSource; end; end; procedure TForm1.VideoGrabber1Log(Sender: TObject; LogType: TLogType; Severity: TLogSeverity; const InfoMsg: string); begin // 把 SDK 内部日志输出到调试窗口,排错时非常有用 OutputDebugString(PChar(Format('[TVG][%d] %s', [Ord(Severity), InfoMsg]))); end; end.

逻辑说明:FormCreate里做三件事——指定视频源类型为采集设备、指定渲染器为 VMR9、把预览窗口句柄交给 Panel1。Button1Click里用IsVideoSourceOpen做状态判断,避免重复打开导致异常。OnLog事件是排错入口,SDK 内部很多状态变化和错误都会往这里抛。

参数说明:VideoDevice是设备索引,不是设备名,多摄像头环境下需要先枚举再赋值;VideoRenderer可选 VMR7、VMR9、EVR 等,Win10 以上建议 VMR9 或 EVR,老系统用 VMR7 兼容性更好;StretchPreview控制是否拉伸填满预览窗口,做比例保持时应该关掉,自己算黑边。

2.4 设备枚举与格式选择

实际项目里不能假设设备索引 0 就是你要的摄像头。常见做法是先枚举:

var i: Integer; begin ComboBox1.Items.Clear; for i := 0 to VideoGrabber1.VideoDevicesCount - 1 do ComboBox1.Items.Add(VideoGrabber1.VideoDeviceName[i]); if ComboBox1.Items.Count > 0 then ComboBox1.ItemIndex := 0; end;

VideoDevicesCount和VideoDeviceName是成对使用的,枚举完让用户选,再把选中索引赋给VideoDevice。格式选择上,VideoGrabber1.VideoWidth和VideoHeight可以指定期望分辨率,但最终能不能用取决于设备支持的媒体类型。如果设了一个设备不支持的分辨率,SDK 会回退到最接近的可用格式,这时候要通过OnVideoDeviceSelected或日志确认实际生效的参数,别默认自己设的就一定生效。

3. 录像、抓帧与推流:参数怎么设才不翻车

3.1 录像文件切分与编码器选择

录像功能的核心属性是RecordingFileName、RecordingMode和RecordingMethod。我一般这样配:

VideoGrabber1.RecordingFileName := 'D:\Rec\cam01_' + FormatDateTime('yyyymmdd_hhnnss', Now) + '.mp4'; VideoGrabber1.RecordingMode := rm_MP4; VideoGrabber1.RecordingMethod := rmm_Recompress; VideoGrabber1.VideoCompressor := vc_H264; VideoGrabber1.AudioCompressor := ac_AAC; VideoGrabber1.StartRecording;

rm_MP4指定容器格式,rmm_Recompress表示重新编码而不是直接存原始流。重新编码的好处是文件小、兼容性好,代价是吃 CPU。如果机器性能紧张,可以改成rmm_NoRecompress,但这样录出来的文件格式取决于采集设备输出,后期播放器兼容性要自己验证。

自动切分用RecordingSplitMode和RecordingSplitSize或RecordingSplitDuration。比如按 10 分钟切:

VideoGrabber1.RecordingSplitMode := rsm_Duration; VideoGrabber1.RecordingSplitDuration := 600; // 单位秒

注意:切分时 SDK 会在后台关闭当前文件并打开新文件,这期间如果磁盘 IO 跟不上,可能丢帧。建议录像目录单独放一块盘,别和系统盘混用。

3.2 抓帧保存为图片的两种路径

抓帧有两种常见需求:一是手动点按钮抓一张,二是按固定间隔自动抓。手动抓用:

VideoGrabber1.BMPSaveToFile := 'D:\Snap\snap_' + FormatDateTime('hhnnsszzz', Now) + '.bmp'; VideoGrabber1.SaveFrameToFile;

如果要 JPEG,把BMPSaveToFile换成JPGSaveToFile,并通过JPGSaveQuality控制质量,取值 0 到 100,工业检测一般 85 到 95 够用,再高文件体积涨得快但肉眼区别不大。

自动抓帧用定时器配合SaveFrameToFile,但要注意别在预览线程里直接调,容易和渲染抢资源。我一般用TTimer在主线程触发,间隔不低于 200ms,否则某些采集卡会报设备忙。

3.3 网络流与 RTSP 的接入要点

TVideoGrabber 也支持把网络流当视频源。设置VideoSource := vs_IPCamera或类似枚举,然后填 URL。实际项目里 RTSP 接入最常见的坑是延迟和断流重连。延迟方面,可以调NetworkLatency或缓冲相关属性,但调太小会卡顿,调太大延迟高,需要根据场景权衡。断流重连我一般自己写一个看门狗定时器,检测IsVideoSourceOpen状态,发现断了就CloseVideoSource再OpenVideoSource,而不是指望 SDK 自动恢复。

推流方面,SDK 支持把采集内容推到 RTMP 等目标。配置项集中在NetworkStreaming相关属性里,需要填目标地址和流密钥。这块我踩过的坑是:推流和本地录像同时开,CPU 占用会明显上升,如果编码器选的是软件 H264,低配机器可能扛不住。解决办法是优先用设备硬件编码,或者降低推流分辨率,别和本地录像用同一路高码率。

4. 避坑与排查:Delphi 12.3 集成 TVideoGrabber 的五个高频问题

4.1 预览黑屏但日志显示设备已打开

现象:调用OpenVideoSource和StartPreview后,Panel 上什么都没有,日志里也没有明显报错。

原因:最常见的是PreviewWindow句柄赋值时机不对。如果在窗体还没创建完、Panel 句柄还没生成时就赋值,SDK 拿到的是无效句柄。另一个原因是渲染器和系统不兼容,比如在 Win10 上用了过老的 VMR7。

解决:把PreviewWindow := Panel1.Handle放到FormShow或Panel1的OnResize之后,确保句柄有效。渲染器优先试 VMR9,不行换 EVR。还可以在赋值后调一次VideoGrabber1.UpdatePreview强制刷新。

4.2 编译期报找不到单元或包冲突

现象:打开示例工程编译,提示找不到VideoGrabber.dcu或某个单元,或者提示包版本冲突。

原因:Delphi 12.3 的库路径里可能残留了旧版本 TVideoGrabber 的路径,或者 SDK 的源码目录没加到Library Path。另外,如果之前装过其他版本的包,设计期包可能冲突。

解决:先在Component > Install Packages里把所有 TVideoGrabber 相关的包移除,再清理Library Path里的旧路径,重新编译安装当前版本的包。确认 Win32 和 Win64 的路径分开配置,不要互相污染。

4.3 录像文件能生成但播放器打不开

现象:录像正常停止,文件也有体积,但用播放器打开提示格式不支持或文件损坏。

原因:多半是录像没有正常停止就退出了程序,文件头没写完。TVideoGrabber 在StopRecording时会做文件收尾,如果程序直接被杀进程,MP4 的 moov box 写不进去,文件就废了。

解决:在窗体OnClose或OnDestroy里确保调用StopRecording,并且给它一点时间完成。如果程序可能被强制结束,考虑用rmm_NoRecompress存原始流,或者改用对异常结束容忍度更高的容器格式。另外,录像过程中别去手动改RecordingFileName,容易把文件句柄搞乱。

4.4 多摄像头同时采集时某个设备打不开

现象:单摄像头正常,同时开两个就有一个报错或黑屏。

原因:一是 USB 带宽不够,两个高分辨率摄像头挂在同一个 USB 控制器下,带宽被占满。二是某些摄像头驱动不支持多实例。三是 SDK 的设备索引在热插拔后变了,代码里还按旧索引打开。

解决:先确认硬件层面,把摄像头插到不同的 USB 控制器上,或者降低其中一个的分辨率。软件层面,每次打开前重新枚举设备,用设备名匹配而不是固定索引。如果驱动不支持多实例,换摄像头或换采集卡。

4.5 程序退出时报内存泄漏或线程未结束

现象:关闭程序时 Delphi 报内存泄漏,或者调试器显示有线程还在运行。

原因:TVideoGrabber 内部有采集线程和渲染线程,如果只调CloseVideoSource而没有先StopPreview和StopRecording,线程可能没完全退出。另外,事件回调里如果引用了已经释放的窗体对象,也会出问题。

解决:退出顺序固定为StopRecording→StopPreview→CloseVideoSource,然后再释放组件。事件回调里尽量只做数据传递,不要直接操作可能已经销毁的 UI 对象。如果用了OnLog之类的回调,在窗体销毁前把事件置空。

5. 进阶技巧:用日志和状态机把采集稳定性拉满

TVideoGrabber 的OnLog事件是我用得最多的排错工具,但很多人只把它当调试输出,其实可以做成运行时的状态监控。我的习惯是:在OnLog里过滤出Severity为警告和错误的条目,写入一个环形缓冲区,界面上放一个小指示灯,有错误就变红。这样现场部署时,不用连调试器也能知道采集链路有没有出问题。

更进一步,我会给采集流程写一个显式状态机,而不是靠一堆布尔标志。状态大致是:Idle、Opening、Previewing、Recording、Error。每次调用 SDK 方法前先检查当前状态是否允许该操作,操作结果通过OnLog和OnVideoDeviceSelected等事件回写状态。这样做的好处是,多线程环境下不会出现“以为已经打开了其实还在打开中”的竞态。下面是一个简化的状态判断片段:

type TCaptureState = (csIdle, csOpening, csPreviewing, csRecording, csError); procedure TForm1.UpdateState(NewState: TCaptureState); begin FState := NewState; case FState of csIdle: StatusLabel.Caption := '空闲'; csOpening: StatusLabel.Caption := '打开中'; csPreviewing:StatusLabel.Caption := '预览中'; csRecording: StatusLabel.Caption := '录像中'; csError: StatusLabel.Caption := '异常'; end; end; procedure TForm1.ButtonOpenClick(Sender: TObject); begin if FState <> csIdle then Exit; UpdateState(csOpening); try VideoGrabber1.VideoDevice := GetSelectedDeviceIndex; VideoGrabber1.OpenVideoSource; VideoGrabber1.StartPreview; UpdateState(csPreviewing); except on E: Exception do begin UpdateState(csError); OutputDebugString(PChar('Open failed: ' + E.Message)); end; end; end;

参数和逻辑说明:FState是窗体私有字段,所有对 SDK 的操作都先过状态判断。GetSelectedDeviceIndex是自己封装的函数,从下拉框取当前设备索引。异常捕获里不要只弹框,一定要写日志,因为现场往往没人看弹框。

另一个进阶点是录像文件的命名和归档策略。我一般用「设备名 + 日期 + 班次 + 序号」的规则,避免纯时间戳在跨天时排序混乱。同时给录像目录设一个容量阈值,超过就删最旧的文件,这个逻辑放在单独的定时器里,别和采集线程耦合。

最后说一个我自己的习惯:每次升级 SDK 版本,先在一个独立的小工程里跑通预览、录像、抓帧三个基本功能,再往主工程里合。因为视频采集这条链路,版本升级带来的行为变化有时候不会写在更新说明里,只有跑一遍才知道。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表