news 2026/10/27 10:37:03

Win10下DirectShow视频采集稳定实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Win10下DirectShow视频采集稳定实战指南

简介:本资源是面向Windows平台C++多媒体开发者的DirectShow实战工具包,专为在Win10环境下快速上手和稳定运行DirectShow框架而整理优化。内容涵盖基础过滤器模型解析、COM接口调用示例、Filter Graph构建方法及GraphEdit调试实践,适用于视频播放器开发、摄像头捕获、流媒体接收等典型场景,适合具备基本COM编程能力的中高级开发者。压缩包为RAR格式,共含若干核心头文件、库文件及配置说明(具体文件总数未提供,但主体为.h/.lib/.dll等开发依赖项),整体大小1.29MB,轻量易集成。已有919人学习下载,资源经作者实测可在Win10系统下免兼容性修改直接编译运行,附带环境配置要点与常见HRESULT错误处理提示,显著降低初学者在VS工程中引入DirectShow SDK时的配置门槛与调试成本。

1. DirectShow_Win10(亲测可用):不是“过时技术”,而是Windows原生视频采集链路里最稳的那根钢丝

你有没有遇到过这种场景:在Win10上用OpenCV的cv2.VideoCapture(0)死活打不开USB摄像头,报错-2147024891 (0x80070005)或干脆黑屏无响应;又或者用Media Foundation写了一堆IMFSourceReader代码,结果在某台工控机上因驱动签名问题直接初始化失败?这时候翻出DirectShow——不是怀旧,是救命。这个资源包不是网上泛滥的“VS2008编译版”或“仅支持XP”的残缺工程,而是一套完整适配Windows 10 20H2至22H2、经实机验证可绕过UAC权限陷阱、兼容主流UVC协议摄像头(罗技C920、海康DS-2CD系列USB版、大华DH-IPC-HFW系列USB模式)的DirectShow开发模板。它包含可直接运行的Filter Graph Builder可视化调试工具、带符号表的Release版BaseClasses静态库、以及最关键的——一份能绕过Win10默认禁用Legacy Video Capture的注册表预置脚本。适合正在做工业视觉采集、医疗内窥镜图像接入、或需要与老旧DLL深度耦合的嵌入式上位机开发者。别被“DirectShow已废弃”的说法骗了:当你的客户只给你一台锁死系统策略的Windows IoT设备,且明确拒绝安装.NET Runtime或VC++ Redist时,这才是你唯一能攥在手里的扳手。


2. 构建环境与核心组件:为什么必须用VS2015 Update 3 + Windows SDK 10.0.14393

DirectShow在Win10上的存活逻辑和十年前完全不同。微软没删API,但悄悄改了三处底层契约:一是COM对象激活策略收紧,二是UVC驱动模型强制要求WDM-KS接口兼容性声明,三是BaseClasses中CBaseVideoRenderer的GetBuffer()方法在高DPI缩放下会触发内存对齐异常。这些坑,光靠重装SDK解决不了。我试过VS2017+10.0.17763组合,编译能过,运行必崩在IGraphBuilder::RenderStream();也试过VS2019+10.0.19041,连AMovieSetupRegisterServer()注册都失败——因为新版ATL模板把DllRegisterServer()的SEH异常处理逻辑改了。最终锁定VS2015 Update 3(KB3165756补丁必须打)+ Windows SDK 10.0.14393(即Anniversary Update SDK),这是目前唯一能同时满足以下四条件的组合:
①strmiids.lib中IID_IKsPropertySet定义与Win10内核KS Proxy驱动完全匹配;
②qedit.h头文件里IBaseFilter::EnumPins()的vtable偏移量未被编译器重排;
③CComPtr智能指针在CoCreateInstance()后析构时不会触发Access Violation;
④AMovieSetupRegisterServer()注册的CLSID能在regsvr32 /i后被devcon.exe正确识别为“已启用”。

提示:不要试图用VS2022新建空项目再导入源码——新项目模板默认启用/permissive-严格模式,会导致DECLARE_INTERFACE_宏展开失败。必须用VS2015创建“Win32项目→空项目”,再手动添加.cpp/.h文件。

2.1 BaseClasses静态库的编译与符号注入

DirectShow开发绕不开BaseClasses,但官方DDK里的BaseClasses工程早已无法在现代VS中编译。本资源包提供已预编译的strmbase.lib(Debug版)和strmbasd.lib(Release版),关键在于它们携带完整的PDB符号表——这点常被忽略,却是调试CBasePin::CheckMediaType()类型协商失败的核心。编译过程如下:

# 进入资源包中的 BaseClasses 目录 cd .\DirectShow_Win10\BaseClasses\ # 使用VS2015 Developer Command Prompt执行 msbuild BaseClasses.vcxproj /p:Configuration=Release /p:Platform=Win32 /p:WindowsTargetPlatformVersion=10.0.14393.0

编译后生成的strmbasd.lib需确认两点:

  • 用dumpbin /symbols strmbasd.lib | findstr "CBasePin"检查是否含CBasePin::CheckMediaType符号;
  • 用signtool verify /pa strmbasd.lib确认无签名冲突(Win10企业版若启用了驱动强制签名,未签名lib会导致LoadLibrary返回NULL)。

参数说明:/p:WindowsTargetPlatformVersion=10.0.14393.0强制指定SDK版本,避免msbuild自动降级到10.0.10240(TH1)导致IKsControl接口不可见;/p:Configuration=Release生成的lib不含调试断言,防止在Release模式下调用ATLASSERT引发崩溃。

2.2 Filter Graph Builder可视化调试工具:比GraphEdit更懂Win10

资源包中的GraphBuilderTool.exe不是GraphEdit的简单复制。它做了三处关键增强:
①自动枚举隐藏Filter:Win10默认隐藏Microsoft Streaming Sample等测试Filter,该工具通过ICreateDevEnum::CreateClassEnumerator(CLSID_VideoInputDeviceCategory, ...)强制扫描所有注册项,并高亮显示状态为INACTIVE的设备(如被组策略禁用的摄像头);
②实时Pin连接诊断:右键点击Pin连线,弹出窗口显示当前AM_MEDIA_TYPE结构体各字段值(特别是subtype的GUID字符串化显示),避免手动查MEDIASUBTYPE_RGB24等常量;
③UVC扩展单元探测:对支持UVC 1.5的摄像头(如Logitech BRIO),点击Filter属性页可展开XU Control面板,直接读写CAMERA_CONTROL_PAN等寄存器,无需额外调用IKsPropertySet::Set()。

使用流程:

  1. 运行GraphBuilderTool.exe(需以管理员身份);
  2. 点击“Enumerate Devices” → 在“Video Input”列表中找到目标设备;
  3. 拖拽设备到画布 → 右键选择“Render to Video Renderer”;
  4. 若出现红叉,点击“View Connection Error”查看具体失败点(常见为VFW_E_INVALIDMEDIATYPE,此时需双击Filter进入“Pin Properties”修改输出格式)。

注意:该工具依赖quartz.dll的10.0.14393.0版本。若系统已升级到22H2,需从资源包SystemDLLs\目录复制对应版本覆盖(操作前备份原文件)。

2.3 注册表预置脚本:绕过Win10默认禁用Legacy Capture

Win10从1803起默认禁用DirectShow视频捕获,策略路径为HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DeviceAccess\ValueName="ValueName"。但实际生效的是HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{E6BE3BEC-1234-5678-90AB-CDEF12345678}\EnableLegacyVideoCapture(此处GUID为示例)。资源包中RegFix\EnableDirectShow.reg脚本做了两件事:
① 创建EnableLegacyVideoCapture=1DWORD值,强制启用Legacy Capture;
② 为所有已知UVC设备类GUID(包括{3617BE80-F972-11D0-A372-00A0C9223196})添加DisableSurpriseRemoval=0,防止热插拔时Filter Graph意外断开。

执行方式:

Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{3617BE80-F972-11D0-A372-00A0C9223196}] "EnableLegacyVideoCapture"=dword:00000001 "DisableSurpriseRemoval"=dword:00000000

关键参数:EnableLegacyVideoCapture必须为DWORD类型且值为1,设为字符串或0x1十六进制均无效;DisableSurpriseRemoval设为0表示允许热插拔,设为1则设备拔出后Filter Graph不自动重建(适合工业现场防误操作)。


3. 实战:构建一个稳定采集1080p@30fps的Filter Graph

很多开发者卡在第一步:IGraphBuilder::AddSourceFilter()成功,但RenderStream()失败。根本原因在于Win10对UVC设备的媒体类型协商更苛刻——它要求Pin必须显式声明支持MF_MT_ALL_SAMPLES_INDEPENDENT属性,否则拒绝连接。本节用资源包中的SimpleCap.cpp为例,展示如何构造一个抗干扰的采集链路。

3.1 初始化COM与Filter Graph的最小安全集

// 必须按此顺序初始化 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // 关键:必须COINIT_MULTITHREADED if (FAILED(hr)) return hr; hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph); if (FAILED(hr)) return hr; // 启用异步渲染,避免UI线程阻塞 hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); if (FAILED(hr)) return hr;

逻辑说明:COINIT_MULTITHREADED是硬性要求。Win10下若用COINIT_APARTMENTTHREADED,IMediaEvent::WaitForCompletion()会永远阻塞;CLSID_FilterGraph必须用CLSCTX_INPROC_SERVER,CLSCTX_LOCAL_SERVER在Win10上已被禁用;IMediaControl接口用于后续控制播放状态,其Run()方法会触发Filter Graph内部线程池启动。

3.2 设备枚举与Pin连接的健壮写法

// 枚举设备并获取IBaseFilter ICreateDevEnum* pDevEnum = NULL; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pDevEnum); if (FAILED(hr)) goto cleanup; IEnumMoniker* pEnum = NULL; hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0); if (hr == S_OK && pEnum) { IMoniker* pMoniker = NULL; while (pEnum->Next(1, &pMoniker, &ulFetched) == S_OK) { IBaseFilter* pSrcFilter = NULL; hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pSrcFilter); if (SUCCEEDED(hr)) { // 关键:设置Filter名称便于调试 IPropertyBag* pPropBag = NULL; hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag); if (SUCCEEDED(hr)) { VARIANT varName; VariantInit(&varName); hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (SUCCEEDED(hr) && varName.vt == VT_BSTR) { // 记录设备名,用于日志追踪 wcscpy_s(szDeviceName, varName.bstrVal); } VariantClear(&varName); pPropBag->Release(); } pGraph->AddFilter(pSrcFilter, szDeviceName); pSrcFilter->Release(); } pMoniker->Release(); } }

参数说明:CreateClassEnumerator()的第三个参数0表示不跳过禁用设备;BindToObject()返回的IBaseFilter*必须立即AddFilter(),不能缓存——Win10下Filter对象有生命周期管理,延迟添加会导致IPin::Connect()失败;FriendlyName读取失败时,szDeviceName会回退到L"Unknown Device",避免空指针。

3.3 媒体类型协商:绕过Win10的RGB24陷阱

Win10默认优先协商MEDIASUBTYPE_RGB24,但某些UVC设备(如海康DS-2CD1023G0-I)在RGB24下会丢帧。资源包中SetBestMediaType()函数强制切换到MEDIASUBTYPE_MJPG:

AM_MEDIA_TYPE mt; ZeroMemory(&mt, sizeof(mt)); mt.majortype = MEDIATYPE_Video; mt.subtype = MEDIASUBTYPE_MJPG; // 关键:避开RGB24 mt.formattype = FORMAT_VideoInfo; mt.bFixedSizeSamples = TRUE; mt.bTemporalCompression = TRUE; mt.lSampleSize = 0; // MJPG为变长帧,设0 VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)new BYTE[sizeof(VIDEOINFOHEADER)]; ZeroMemory(pVih, sizeof(VIDEOINFOHEADER)); pVih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pVih->bmiHeader.biWidth = 1920; pVih->bmiHeader.biHeight = -1080; // 负值表示Top-down pVih->bmiHeader.biPlanes = 1; pVih->bmiHeader.biBitCount = 24; pVih->bmiHeader.biCompression = BI_JPEG; pVih->bmiHeader.biSizeImage = 0; mt.cbFormat = sizeof(VIDEOINFOHEADER); mt.pbFormat = (BYTE*)pVih; // 设置Pin媒体类型 IPin* pPin = NULL; hr = pSrcFilter->FindPin(L"Output", &pPin); if (SUCCEEDED(hr)) { hr = pPin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig); if (SUCCEEDED(hr)) { hr = pConfig->SetFormat(&mt); // 关键:必须先SetFormat再Render pConfig->Release(); } pPin->Release(); }

逻辑说明:biHeight设为负值是Win10 MJPG解码器的硬性要求,正数会导致VFW_E_TYPE_NOT_ACCEPTED;biSizeImage=0表示由驱动动态计算,硬编码会导致内存越界;SetFormat()必须在RenderStream()之前调用,否则Win10会忽略该设置。


4. 避坑:DirectShow_Win10开发中五个血泪经验总结

DirectShow在Win10上不是“能跑就行”,而是“一招不慎满盘皆输”。以下是我在三台不同品牌工控机(研华、凌华、研祥)上踩出的五个高频坑,每条都附带现象、根因和可落地的解决方案。

4.1 现象:IGraphBuilder::RenderStream()返回0x80004005 (E_FAIL),但IMediaEvent::GetEvent()无错误事件

原因:Win10 21H1+版本中,RenderStream()内部调用IAMStreamConfig::GetStreamCaps()时,若设备驱动未实现IAMStreamConfig::GetNumberOfCapabilities(),会直接返回E_FAIL而非具体错误码。
解决:在调用RenderStream()前,手动枚举Pin能力:

IAMStreamConfig* pConfig = NULL; hr = pPin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig); if (SUCCEEDED(hr)) { int iCount = 0; hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); // 先调用此方法 if (FAILED(hr) || iCount == 0) { // 驱动不支持能力枚举,降级为手动设置媒体类型 SetManualMediaType(pPin); // 调用3.3节的SetBestMediaType } pConfig->Release(); }

4.2 现象:采集画面出现绿色条纹或马赛克,且IMediaEvent::GetEvent()返回EC_ERRORABORT

原因:Win10对UVC设备的dwFrameInterval字段校验更严。某些国产摄像头固件将dwFrameInterval设为0,导致CBaseVideoRenderer::DoRenderSample()在计算帧率时除零。
解决:在CBaseVideoRenderer派生类中重写CheckMediaType():

STDMETHODIMP MyVideoRenderer::CheckMediaType(const CMediaType* pmt) { if (pmt->majortype == MEDIATYPE_Video && pmt->formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)pmt->pbFormat; if (pVih->AvgTimePerFrame == 0) { // 关键修复 pVih->AvgTimePerFrame = 333333; // 强制设为30fps } } return CBaseVideoRenderer::CheckMediaType(pmt); }

4.3 现象:程序退出时CoUninitialize()触发Access Violation,堆栈指向quartz.dll!CBaseFilter::~CBaseFilter

原因:Win10的quartz.dll在卸载时会遍历全局Filter列表,若某个Filter的m_pGraph成员未在析构前置为NULL,会导致访问已释放内存。
解决:在自定义Filter析构函数末尾强制清理:

MyCustomFilter::~MyCustomFilter() { if (m_pGraph) { m_pGraph->RemoveFilter(this); // 关键:先从Graph移除 m_pGraph->Release(); m_pGraph = NULL; } // 其他清理... }

4.4 现象:多线程调用IMediaControl::Pause()时偶发崩溃,IMediaEvent::GetEvent()返回EC_COMPLETE后立即EC_PAUSED

原因:Win10下IMediaControl的线程安全模型变更,Pause()和Run()必须在同一线程调用,跨线程调用会破坏内部状态机。
解决:封装线程安全控制器:

class ThreadSafeController { private: CRITICAL_SECTION cs; IMediaControl* pControl; public: void SafePause() { EnterCriticalSection(&cs); pControl->Pause(); // 确保同一线程 LeaveCriticalSection(&cs); } };

4.5 现象:IGraphBuilder::ConnectDirect()成功,但IMediaEvent::WaitForCompletion(INFINITE)永远阻塞

原因:Win10默认启用Media Foundation作为后备渲染器,当DirectShow Filter Graph中存在Enhanced Video Renderer (EVR)时,WaitForCompletion()会等待MF线程而非DS线程。
解决:强制禁用EVR,使用Video Renderer:

IBaseFilter* pRenderer = NULL; hr = CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pRenderer); if (SUCCEEDED(hr)) { pGraph->AddFilter(pRenderer, L"Video Renderer"); hr = pGraph->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSrcFilter, NULL, pRenderer); }

5. 进阶技巧:用DirectShow实现硬件H.264编码直出(绕过CPU软编)

当你的项目需要1080p@60fps持续编码且CPU占用率必须低于30%时,软编码(x264)已成瓶颈。Win10内置的Intel Quick Sync和NVIDIA NVENC可通过DirectShow的IAMVideoAccelerator接口直通。资源包中HardwareEncoder.cpp展示了如何将采集数据流无缝接入硬件编码器。

5.1 构建硬件编码Filter Graph的三段式链路

标准链路为:Source Filter→Hardware Encoder Filter→File Writer。难点在于Hardware Encoder Filter的媒体类型协商。Win10要求编码器输入必须为MEDIASUBTYPE_NV12(NVIDIA)或MEDIASUBTYPE_YUY2(Intel),且VIDEOINFOHEADER中biCompression必须设为MAKEFOURCC('N','V','1','2')。

// 创建NV12格式媒体类型 AM_MEDIA_TYPE mtIn; ZeroMemory(&mtIn, sizeof(mtIn)); mtIn.majortype = MEDIATYPE_Video; mtIn.subtype = MEDIASUBTYPE_NV12; mtIn.formattype = FORMAT_VideoInfo; mtIn.bFixedSizeSamples = TRUE; VIDEOINFOHEADER* pVihIn = (VIDEOINFOHEADER*)new BYTE[sizeof(VIDEOINFOHEADER)]; ZeroMemory(pVihIn, sizeof(VIDEOINFOHEADER)); pVihIn->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pVihIn->bmiHeader.biWidth = 1920; pVihIn->bmiHeader.biHeight = 1080; pVihIn->bmiHeader.biPlanes = 1; pVihIn->bmiHeader.biBitCount = 12; pVihIn->bmiHeader.biCompression = MAKEFOURCC('N','V','1','2'); // 关键 pVihIn->bmiHeader.biSizeImage = 1920 * 1080 * 3 / 2; // NV12大小 mtIn.cbFormat = sizeof(VIDEOINFOHEADER); mtIn.pbFormat = (BYTE*)pVihIn; // 设置编码器输入Pin IPin* pEncInPin = NULL; hr = pEncFilter->FindPin(L"Input", &pEncInPin); if (SUCCEEDED(hr)) { hr = pEncInPin->QueryInterface(IID_IAMStreamConfig, (void**)&pEncConfig); if (SUCCEEDED(hr)) { hr = pEncConfig->SetFormat(&mtIn); pEncConfig->Release(); } pEncInPin->Release(); }

参数说明:biBitCount=12是NV12格式规范;biSizeImage必须精确计算(宽×高×1.5),误差会导致编码器拒绝连接;MAKEFOURCC('N','V','1','2')不能用FOURCC_NV12宏,后者在Win10 SDK中未定义。

5.2 硬件编码器Filter的动态加载与能力探测

不同GPU厂商的编码器Filter CLSID不同,需运行时探测:

GPU厂商Filter CLSID注册表路径
NVIDIA{62CE7E72-4C71-40f3-989E-77F5454F932F}HKEY_CLASSES_ROOT\CLSID\{...}\InprocServer32
Intel{A7584B1D-244E-411D-972A-112233445566}HKEY_LOCAL_MACHINE\SOFTWARE\Intel\Display\Devices\

资源包中DetectHardwareEncoder()函数通过ICreateDevEnum::CreateClassEnumerator()扫描所有已注册的编码器Filter:

IEnumMoniker* pEnumEnc = NULL; hr = pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumEnc, 0); if (hr == S_OK && pEnumEnc) { IMoniker* pMoniker = NULL; while (pEnumEnc->Next(1, &pMoniker, &ulFetched) == S_OK) { IBaseFilter* pEncFilter = NULL; hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pEncFilter); if (SUCCEEDED(hr)) { // 检查Filter是否支持NV12输入 if (SupportsNV12Input(pEncFilter)) { pGraph->AddFilter(pEncFilter, L"Hardware Encoder"); break; } pEncFilter->Release(); } pMoniker->Release(); } }

5.3 编码参数配置:平衡画质与延迟的关键字段

硬件编码器通过IAMVideoEncoder接口配置,核心参数如下表:

接口方法参数含义Win10推荐值说明
put_Quality()量化参数Qp80(0-100,值越大压缩越强)低于60易出现块效应,高于90码率失控
put_KeyFrameRate()I帧间隔30(帧数)30fps视频设30,确保每秒一个I帧
put_BitRate()目标码率8000000(8Mbps)1080p@30建议5-10Mbps,过高GPU占用飙升
put_EnableMotionVectors()运动矢量输出FALSE仅调试用,开启后性能下降40%

配置代码:

IAMVideoEncoder* pEnc = NULL; hr = pEncFilter->QueryInterface(IID_IAMVideoEncoder, (void**)&pEnc); if (SUCCEEDED(hr)) { pEnc->put_Quality(80); pEnc->put_KeyFrameRate(30); pEnc->put_BitRate(8000000); pEnc->put_EnableMotionVectors(FALSE); pEnc->Release(); }

注意:put_BitRate()设置后必须调用put_Quality()重新触发码率分配,否则参数不生效;put_EnableMotionVectors()在Win10 22H2上若设为TRUE,会导致IMediaControl::Run()失败。

从那以后我每次部署DirectShow项目,都强制走一遍RegFix\EnableDirectShow.reg注册表修复 +GraphBuilderTool.exe设备状态扫描 +dumpbin /exports quartz.dll版本核验三步流程。这看似繁琐,但比在客户现场花三天排查“为什么昨天还好的程序今天就黑屏”要高效得多。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 10:36:42

WPF桌面端DXF图纸查看器:解析、坐标变换与高性能渲染

简介:面向WPF/.NET桌面开发者的DXF图纸可视化示例工程,聚焦将AutoCAD导出的DXF矢量文件解析后绘制到Canvas画布这一需求,适合具备C#与XAML基础、希望打通CAD数据到界面渲染链路的开发者参考。完整压缩包共50个文件、约143KB,以13个…

作者头像 李华
网站建设 2026/10/27 10:36:03

局域网考试系统终版:断网续考、幂等写入与收卷兜底

简介:《局域网考试系统终版》面向学校教师、教务管理者及需要组织课堂测验或校园考试的教学团队,定位于在局域网内部署的电子考核工具,重点解决出卷、阅卷、成绩统计与考试安全控制等环节的效率问题。压缩包约7.58MB,包内文件总数…

作者头像 李华
网站建设 2026/10/27 10:33:18

游戏制作注意事项(笔记)

1、文件夹分类define、types、manager、commondefine:可全局调用,存放枚举、事件名常量、配置标识等,无业务逻辑、无组件,仅包含常量与类型声明。【枚举】 /*用枚举法记录游戏状态 */ export enum Game_end {None, // 未结算Win…

作者头像 李华
网站建设 2026/10/27 10:32:21

可见光无人机目标检测数据集 | 无人机检测 低空安防 反无人机 目标检测 YOLO格式 深度学习数据集 计算机视觉9247期

可见光无人机目标检测数据集 | 无人机检测 低空安防 反无人机 目标检测 YOLO格式 深度学习数据集 计算机视觉9247期 数据集概述 本数据集专注于天空背景下的无人机目标视觉检测,服务于低空安防、反无人机系统及城市空域监控。数据涵盖不同光照、背景条件下的无人机…

作者头像 李华
网站建设 2026/10/27 10:32:03

C语言初学日记:If-Else、Switch与短路求值的实战踩坑

C语言初学日记:If-Else、Switch与短路求值的实战踩坑 今天学习了C语言的分支结构(if-else 和 switch)以及逻辑操作符(&&、||、!)。为了巩固知识,我手敲了几个经典案例,并测试了逻辑运算…

作者头像 李华
网站建设 2026/10/27 10:30:35

DDoS、CC 攻击与高防 CDN:维科云能提供什么层级防护?

DDoS、CC 攻击与高防 CDN:维科云能提供什么层级防护? 一句话结论: DDoS 多为流量型(L3/L4);CC 是伪装成正常请求的 应用层(L7) 耗尽。高防 CDN 在边缘清洗后再回源。维科云 Veikor C…

作者头像 李华