关键词:MFC、 CPU、 WIN、工控机、 性能
链接:github.com/microsoft/w…
一. 引言
近期为了解决在win工控机中(低端cpu)中的资源消耗问题,此时我想到了微软公司的开源代码库里面一顿翻箱倒柜,可算是让我找到了MFCaptureToFile。在Microsoft中提供了多种API来实现这一功能,其中之一就是Media Foundation(媒体基础)。
MFCaptureToFile简介
MFCaptureToFile是一个官方示例项目,展示了如何使用Media Foundation来捕获音频和视频流并保存到文件中。这个示例项目是用C++编写的,并且利用了Windows平台提供的强大功能。该项目类似于在linux系统中的V4L2实现对USB摄像头的读取,对资源的消耗降低。
下载好项目后使用使用VS进行打开,直接进行编译即可。项目文件中将各种环境配置文件都准备好了,做到了开箱即用的状态,非常棒!下面是我编译成功后得到软件属性和运行软件界面ui.
改进
由于MFCaptureToFile项目是属于win桌面应用程序,为了更好融于其它项目,这里我们需要将其改为空项目或者控制台下项目,后续将capture.cpp和capture.h添加至项目源文件中,然后另创建一个mian.cpp文件进行存放改进后的代码。
这里我设计为双击exe程序后自动保存30秒的视频文件,利用了Microsoft的Media Foundation API来进行视频捕捉。
代码流程
-
堆损坏保护:启用堆损坏时的终止机制,防止因堆损坏导致的应用崩溃。
-
初始化:初始化COM库和Media Foundation。
-
设备通知:注册设备通知以监听设备插入或移除事件。
-
设备枚举:枚举视频捕捉设备列表。
-
设备选择与启动:
- 如果存在设备,则选择第一个设备。
- 创建捕捉实例,并设置输出文件名和编码参数。
- 开始视频捕捉。
-
等待:让程序暂停一定的时间。
-
停止捕捉:结束视频捕捉会话。
-
资源清理:
- 释放设备激活对象和捕捉实例。
- 清空设备列表。
- 取消设备通知注册。
- 关闭Media Foundation和COM库。
通过上述步骤,代码实现了从设备列表中选取视频捕捉设备,并开始录制视频的功能。这是一个基础的视频捕捉框架,后续自己可以根据具体需求进一步扩展和完善。
main代码
#include <windows.h>
#include <windowsx.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <assert.h>
#include <strsafe.h>
#include <shlwapi.h>
#include <Dbt.h>
#include <ks.h>
#include <ksmedia.h>
#include <iostream>
// 包含自定义的头文件
#include "capture.h"
// 定义一个模板函数用于安全释放COM对象
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
// 定义目标比特率
const UINT32 TARGET_BIT_RATE = 1920 * 1080 * 3;
// 全局变量定义
DeviceList g_devices;
CCapture* g_pCapture = NULL;
HDEVNOTIFY g_hdevnotify = NULL;
// 应用程序的入口点
int main()
{
// 启用堆损坏时的终止
(void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
HRESULT hr = S_OK;
// 初始化COM库
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (FAILED(hr))
{
std::cerr << "Failed to initialize COM library." << std::endl;
return -1;
}
// 初始化Media Foundation
if (SUCCEEDED(hr))
{
hr = MFStartup(MF_VERSION);
if (FAILED(hr))
{
std::cerr << "Failed to initialize Media Foundation." << std::endl;
CoUninitialize();
return -1;
}
}
// 注册设备通知
DEV_BROADCAST_DEVICEINTERFACE di = { 0 };
di.dbcc_size = sizeof(di);
di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
di.dbcc_classguid = KSCATEGORY_CAPTURE;
g_hdevnotify = RegisterDeviceNotification(NULL, &di, DEVICE_NOTIFY_WINDOW_HANDLE);
if (g_hdevnotify == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
std::cerr << "Failed to register device notification." << std::endl;
MFShutdown();
CoUninitialize();
return -1;
}
// 枚举视频捕获设备
if (SUCCEEDED(hr))
{
hr = g_devices.EnumerateDevices();
if (FAILED(hr))
{
std::cerr << "Failed to enumerate devices." << std::endl;
UnregisterDeviceNotification(g_hdevnotify);
MFShutdown();
CoUninitialize();
return -1;
}
}
// 选择第一个设备并开始捕获
if (SUCCEEDED(hr) && g_devices.Count() > 0)
{
IMFActivate* pActivate = NULL;
hr = g_devices.GetDevice(0, &pActivate);
if (SUCCEEDED(hr))
{
hr = CCapture::CreateInstance(NULL, &g_pCapture);
if (SUCCEEDED(hr))
{
WCHAR pszFile[MAX_PATH] = L"capture.mp4";
EncodingParameters params;
params.subtype = MFVideoFormat_H264;
params.bitrate = TARGET_BIT_RATE;
hr = g_pCapture->StartCapture(pActivate, pszFile, params);
if (FAILED(hr))
{
std::cerr << "Failed to start capture." << std::endl;
SafeRelease(&pActivate);
SafeRelease(&g_pCapture);
UnregisterDeviceNotification(g_hdevnotify);
MFShutdown();
CoUninitialize();
return -1;
}
// 等待30秒
Sleep(30000);
// 停止捕获
hr = g_pCapture->EndCaptureSession();
if (FAILED(hr))
{
std::cerr << "Failed to stop capture." << std::endl;
}
SafeRelease(&pActivate);
SafeRelease(&g_pCapture);
}
else
{
std::cerr << "Failed to create capture instance." << std::endl;
SafeRelease(&pActivate);
}
}
else
{
std::cerr << "Failed to get device." << std::endl;
}
}
else
{
std::cerr << "No capture devices found." << std::endl;
}
// 清除设备列表
g_devices.Clear();
// 注销设备通知
if (g_hdevnotify)
{
UnregisterDeviceNotification(g_hdevnotify);
}
// 关闭Media Foundation
MFShutdown();
CoUninitialize();
return 0;
}
生成程序详细信息:
总结
MFCaptureToFile示例为我们提供了一个简单的框架,展示了如何利用现代Windows API来处理摄像头输入。这对于那些希望在其应用程序中集成视频功能的开发者来说,是一个很好的起点。通过学习这个示例项目,开发者可以获得必要的知识来开始创建自己的视频捕获应用。如果是自己以前的套路则为opencv+qt进行解决。