ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Win10下DirectShow亲测可用资源拆包与避坑指南

Win10下DirectShow亲测可用资源拆包与避坑指南 简介DirectShow_Win10亲测可用是一份面向Windows 10平台多媒体开发者的DirectShow学习与开发资源包适合具备一定C与COM编程基础、希望构建播放器、视频捕获或流媒体应用的开发者。资源围绕DirectShow框架展开涵盖过滤器图工作原理、源/转换/渲染过滤器类型、CoCreateInstance等COM接口调用方式以及在Win10下的安装配置与兼容性要点并延伸至GraphEdit调试、HRESULT错误处理与自定义过滤器开发等实践内容。压缩包为rar格式大小约1.29MB上游未提供文件总数与类型明细但内容以头文件、库文件及配套说明为主可直接集成到Visual Studio项目中配合DirectX SDK使用。目前已有915人学习下载可作为快速搭建DirectShow开发环境、理解过滤器图机制与排查兼容性问题的参考材料。1. DirectShow 在 Win10 上到底还能不能跑一次亲测可用的资源拆包如果你最近在 Win10 上编译过老的多媒体项目大概率见过这个场景代码里#include dshow.h一加链接strmiids.lib一挂编译直接报一堆unresolved external symbol或者运行时CoCreateInstance返回0x80040154类未注册。DirectShow 这套微软的老牌流媒体框架从 DirectX 9 时代一路活到 Win10官方文档还在但真到 Win10 上跑起来坑比想象中多。这份「DirectShow_Win10亲测可用」资源核心价值就是把这套框架在 Win10 环境下的可用状态、依赖组件和最小可运行工程整理清楚了省去你自己一个个试 SDK 版本、试注册表、试 COM 初始化的时间。它适合两类人一是维护老音视频采集/播放项目的工程师二是想用 DirectShow 做摄像头采集、滤镜开发但被环境卡住的新手。下面我按「资源是什么 → 怎么用 → 坑在哪」的顺序把这份包拆开讲。2. DirectShow 在 Win10 的运行时依赖SDK、COM 与注册表三件事2.1 为什么 Win10 上 DirectShow 不是「装上就能用」DirectShow 在 Win10 里并没有被移除quartz.dll、qedit.dll这些核心组件依然躺在C:\Windows\System32下但微软从 Windows SDK 8.0 之后就不再单独提供 DirectShow 的完整头文件和库的「一键安装」了。很多人的第一反应是去装老版本的 DirectX SDK比如 June 2010结果和 Win10 自带的 SDK 冲突dshow.h版本对不上链接期直接翻车。常见做法是不装老 DirectX SDK直接用 Windows SDK 里自带的 DirectShow 头文件但需要手动确认几个关键文件是否齐全。我一般会先检查这几个路径# 检查 Windows SDK 中 DirectShow 相关文件是否存在 dir C:\Program Files (x86)\Windows Kits\10\Include\*\um\dshow.h dir C:\Program Files (x86)\Windows Kits\10\Lib\*\um\x64\strmiids.lib dir C:\Program Files (x86)\Windows Kits\10\Lib\*\um\x64\quartz.lib逻辑说明dshow.h是 DirectShow 的主头文件strmiids.lib提供接口 GUIDquartz.lib提供CoCreateInstance需要的类厂标识。参数说明*代表 SDK 版本号目录比如10.0.19041.0x64 换成 x86 就是 32 位库。如果这三个文件都在说明 SDK 层面没问题不用再折腾老 DirectX SDK。2.2 COM 初始化与线程模型别在错误的地方调 CoInitializeDirectShow 完全基于 COM所以每个使用它的线程都必须先调CoInitializeEx。新手最容易犯的错是在主线程初始化了然后在工作线程里直接调IGraphBuilder结果返回CO_E_NOTINITIALIZED。正确做法是每个线程各自初始化并且注意套间模型。// 每个使用 DirectShow 的线程都要独立初始化 COM HRESULT hr CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(hr)) { // RPC_E_CHANGED_MODE 表示该线程已用其他模型初始化过 if (hr ! RPC_E_CHANGED_MODE) { return hr; } } // ... 在这里创建 IGraphBuilder、ICaptureGraphBuilder2 等 CoUninitialize(); // 与 CoInitializeEx 配对逻辑说明COINIT_APARTMENTTHREADED是 STA 模型DirectShow 的很多滤镜尤其是视频渲染器要求 STA。参数说明如果返回RPC_E_CHANGED_MODE说明当前线程已经被初始化成 MTA 了这时不要重复初始化也不要CoUninitialize直接继续用即可但要注意跨套间调用可能带来的封送开销。这个细节在 Win10 上尤其重要因为 Win10 对 COM 套间的检查比 Win7 严格。2.3 注册表里要确认的 Filter 注册状态DirectShow 的滤镜分两类一类是系统自带的注册在HKEY_CLASSES_ROOT\CLSID下另一类是你自己写的需要用regsvr32注册。Win10 上如果发现CoCreateInstance返回0x80040154八成是滤镜没注册或者注册到了错误的位数32 位滤镜注册到 64 位注册表视图。# 以管理员身份注册 32 位滤镜注意用 SysWOW64 下的 regsvr32 C:\Windows\SysWOW64\regsvr32.exe YourFilter.dll # 注册 64 位滤镜 C:\Windows\System32\regsvr32.exe YourFilter.dll # 查询某个 CLSID 是否注册 reg query HKCR\CLSID\{你的CLSID} /s逻辑说明Win10 的注册表有 WOW64 重定向32 位程序看到的HKCR\CLSID和 64 位程序看到的是同一逻辑视图但物理位置不同。参数说明SysWOW64下的regsvr32是 32 位版本System32下的是 64 位版本别搞反。如果查询不到 CLSID说明注册失败常见原因是 DLL 依赖的运行时库缺失用Dependencies工具查一下。3. 最小可运行工程从零搭一个 Win10 下的摄像头预览程序3.1 工程配置头文件、库、字符集三处对齐在 Visual Studio 里新建一个空 C 控制台工程然后按下面三步配置。很多人编译不过不是代码问题是工程配置没对齐。第一步包含目录加上 SDK 的Include\*\um和Include\*\shared。第二步库目录加上Lib\*\um\x64或 x86。第三步在链接器输入里加上strmiids.lib quartz.lib ole32.lib oleaut32.lib。字符集建议用 Unicode因为 DirectShow 的IGraphBuilder::RenderFile在 Win10 上对宽字符路径支持更稳。// 最小摄像头预览枚举设备 - 建图 - 渲染 #include dshow.h #include iostream #pragma comment(lib, strmiids.lib) #pragma comment(lib, quartz.lib) #pragma comment(lib, ole32.lib) int main() { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); ICreateDevEnum* pDevEnum nullptr; IEnumMoniker* pEnum nullptr; // 创建系统设备枚举器 CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)pDevEnum); // 枚举视频采集设备类别 pDevEnum-CreateClassEnumerator(CLSID_VideoInputDeviceCategory, pEnum, 0); IMoniker* pMoniker nullptr; if (pEnum pEnum-Next(1, pMoniker, NULL) S_OK) { IPropertyBag* pBag nullptr; pMoniker-BindToStorage(0, 0, IID_IPropertyBag, (void**)pBag); VARIANT var; VariantInit(var); pBag-Read(LFriendlyName, var, 0); std::wcout L找到设备: var.bstrVal std::endl; VariantClear(var); pBag-Release(); pMoniker-Release(); } // 后续用 IGraphBuilder ICaptureGraphBuilder2 建图此处省略 if (pEnum) pEnum-Release(); if (pDevEnum) pDevEnum-Release(); CoUninitialize(); return 0; }逻辑说明CLSID_SystemDeviceEnum是系统设备枚举器的类标识CLSID_VideoInputDeviceCategory限定只枚举摄像头。参数说明CreateClassEnumerator的第三个参数为 0 表示返回所有设备如果设为CDEF_DEVMON_FILTER则只返回已注册的滤镜。这段代码能跑通说明 COM 和枚举器都正常接下来才是建图。3.2 用 CaptureGraphBuilder2 建图顺序错了就黑屏建图的顺序很关键先CoCreateInstance拿IGraphBuilder再拿ICaptureGraphBuilder2然后SetFiltergraph把两者绑定最后RenderStream。如果先RenderStream再SetFiltergraphWin10 上大概率黑屏或者返回E_INVALIDARG。IGraphBuilder* pGraph nullptr; ICaptureGraphBuilder2* pBuilder nullptr; CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)pGraph); CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)pBuilder); pBuilder-SetFiltergraph(pGraph); // 必须先绑定 // 假设 pCap 是已经创建好的采集滤镜 // pBuilder-RenderStream(PIN_CATEGORY_PREVIEW, MEDIATYPE_Video, pCap, NULL, NULL);逻辑说明SetFiltergraph把 GraphBuilder 和 CaptureGraphBuilder2 关联起来后续RenderStream才能正确找到渲染器。参数说明PIN_CATEGORY_PREVIEW表示预览引脚PIN_CATEGORY_CAPTURE表示采集引脚Win10 上有些摄像头只暴露 capture 不暴露 preview这时要改用 capture 引脚并手动接一个Smart Tee滤镜分流。3.3 消息循环与事件处理别让窗口卡死DirectShow 的图运行起来后需要处理IMediaEvent消息否则窗口会假死。常见做法是在主消息循环里用IMediaEvent::GetEvent轮询或者用IMediaEventEx::SetNotifyWindow把事件转发到窗口过程。IMediaEventEx* pEvent nullptr; pGraph-QueryInterface(IID_IMediaEventEx, (void**)pEvent); pEvent-SetNotifyWindow((OAHWND)hWnd, WM_GRAPHNOTIFY, 0); // 在窗口过程中处理 case WM_GRAPHNOTIFY: { long evCode; LONG_PTR param1, param2; while (pEvent-GetEvent(evCode, param1, param2, 0) S_OK) { if (evCode EC_COMPLETE) { /* 播放结束 */ } pEvent-FreeEventParams(evCode, param1, param2); } break; }逻辑说明SetNotifyWindow把 DirectShow 事件投递到指定窗口避免阻塞主线程。参数说明WM_GRAPHNOTIFY是自定义消息号GetEvent的最后一个参数 0 表示同步获取如果设为INFINITE会阻塞。Win10 上如果发现事件收不到检查窗口句柄是否有效以及是否在正确的线程创建了图。4. 避坑与排查Win10 下 DirectShow 最常见的五个翻车现场4.1 现象编译报dshow.h找不到或链接报strmiids.lib缺失原因Windows SDK 安装时没有勾选「Desktop development with C」里的 Windows SDK 组件或者只装了 UWP 部分的 SDK。解决打开 Visual Studio Installer修改当前 VS 版本在「单个组件」里搜索「Windows SDK」确保对应版本的 SDK 已勾选并且安装路径下确实有um\dshow.h。如果还是找不到检查工程属性里的「Windows SDK 版本」是否选了一个没装全的版本。4.2 现象CoCreateInstance返回0x80040154类未注册原因目标滤镜没有注册或者注册到了错误的注册表视图。解决先用reg query确认 CLSID 是否存在如果不存在用对应位数的regsvr32重新注册如果注册成功但依然报错用Dependencies工具查 DLL 的依赖是否齐全Win10 上常见缺msvcp140.dll或vcruntime140.dll。4.3 现象摄像头预览黑屏但RenderStream返回S_OK原因Win10 的隐私设置里摄像头权限没开或者摄像头被其他程序占用。解决打开「设置 → 隐私 → 摄像头」确认「允许应用访问你的摄像头」已开启然后检查是否有其他程序如 Teams、Zoom正在占用摄像头。如果权限和占用都没问题尝试改用PIN_CATEGORY_CAPTURE加Smart Tee的方式建图。4.4 现象程序运行一段时间后卡死CPU 占用飙升原因IMediaEvent没有及时FreeEventParams导致事件队列堆积或者消息循环里做了阻塞操作。解决确保每次GetEvent成功后都调用FreeEventParams把耗时操作放到独立线程主线程只处理窗口消息和事件轮询。Win10 上还可以用任务管理器看quartz.dll的线程状态确认是否有死锁。4.5 现象32 位程序在 64 位 Win10 上注册滤镜成功但运行时找不到原因32 位程序读取的是HKCR\Wow6432Node\CLSID而 64 位regsvr32注册到了HKCR\CLSID。解决用C:\Windows\SysWOW64\regsvr32.exe重新注册 32 位滤镜然后用reg query HKCR\Wow6432Node\CLSID\{你的CLSID}确认。如果还是不行检查滤镜 DLL 本身是不是 32 位的用dumpbin /headers看 machine 字段。5. 进阶技巧用 GraphEdit 验证滤镜链路与性能调优5.1 用 GraphEdit 快速验证滤镜是否可用GraphEdit 是 Windows SDK 里自带的一个小工具在C:\Program Files (x86)\Windows Kits\10\bin\*\x64\graphedit.exe部分版本需要单独装 SDK 工具。它的价值在于不用写一行代码就能把摄像头、解码器、渲染器拖到一起看链路能不能通。我一般在新环境上先跑 GraphEdit确认系统滤镜都正常再回去调代码。如果 GraphEdit 里都连不通代码里更不可能通。操作步骤打开 GraphEdit → 点「Graph → Insert Filters」→ 在「Video Capture Sources」里选摄像头 → 在「DirectShow Filters」里选Video Renderer→ 把两个滤镜的引脚连起来 → 点播放。如果能看到画面说明系统层面没问题如果报错错误码会直接显示在弹窗里比代码里调试快得多。5.2 性能调优缓冲区、帧率和色彩空间DirectShow 默认的采集缓冲区可能偏小Win10 上高分辨率摄像头容易丢帧。常见做法是通过IAMBufferNegotiation接口调整缓冲区数量或者通过IAMStreamConfig设置帧率和色彩空间。参数默认值建议值说明缓冲区数量13~5太少丢帧太多增加延迟帧率摄像头默认与处理能力匹配太高会占满 CPU色彩空间YUY2MJPG 或 NV12MJPG 省带宽NV12 省 CPU分辨率640x480按需1080p 以上建议用 MJPG// 通过 IAMStreamConfig 设置帧率和分辨率 IAMStreamConfig* pConfig nullptr; pCap-QueryInterface(IID_IAMStreamConfig, (void**)pConfig); int count, size; pConfig-GetNumberOfCapabilities(count, size); VIDEO_STREAM_CONFIG_CAPS caps; AM_MEDIA_TYPE* pmt; for (int i 0; i count; i) { pConfig-GetStreamCaps(i, pmt, (BYTE*)caps); if (pmt-subtype MEDIASUBTYPE_MJPG caps.MaxOutputSize.cx 1280) { pConfig-SetFormat(pmt); // 选中 MJPG 1280 宽 break; } DeleteMediaType(pmt); }逻辑说明GetStreamCaps枚举摄像头支持的所有格式SetFormat应用选中的格式。参数说明MEDIASUBTYPE_MJPG是动态 JPEG适合高分辨率低带宽场景MEDIASUBTYPE_NV12是 YUV 4:2:0适合需要 CPU 处理的场景。Win10 上如果发现设置格式后返回E_INVALIDARG说明摄像头不支持该格式回退到默认即可。5.3 一个我踩过的坑别在 Win10 上混用老 DirectX SDK 和 Windows SDK早期我为了图省事在 Win10 上同时装了 DirectX SDK June 2010 和 Windows SDK结果dshow.h被老 SDK 覆盖编译出来的程序在 Win10 上跑着跑着就崩。后来查了半天才发现是头文件版本冲突。从那以后我每次配新环境都强制先检查dshow.h的路径优先级确保只引用 Windows SDK 里的版本。具体做法是在工程属性里把 Windows SDK 的包含目录移到 DirectX SDK 前面或者干脆不装老 DirectX SDK。这个习惯帮我省了不少后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表