Microsoft Media Foundation 支持音频和视频捕获。 视频捕获设备通过 UVC 类驱动程序受支持,并且必须与 UVC 1.1 兼容。 通过 Windows 音频会话 API(WASAPI)支持音频捕获设备。
捕获设备由媒体源对象在媒体基础中表示,该对象公开 IMFMediaSource 接口。 在大多数情况下,应用程序不会直接使用此接口,但会使用更高级别的 API(如 源读取器)来控制捕获设备。
枚举捕获设备
若要枚举系统上的捕获设备,请执行以下步骤:
调用 MFCreateAttributes 函数来创建属性存储。
将 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 属性设置为以下值之一:
价值 描述 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID 枚举音频捕获设备。 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID 枚举视频捕获设备。 调用 MFEnumDeviceSources 函数。 此函数分配 IMFActivate 指针的数组。 每个指针表示系统上一台设备的激活对象。
调用 IMFActivate::ActivateObject 方法,以从其中一个激活对象创建媒体源的实例。
以下示例为枚举列表中的第一个视频捕获设备创建媒体源:
HRESULT CreateVideoCaptureDevice(IMFMediaSource **ppSource)
{
*ppSource = NULL;
UINT32 count = 0;
IMFAttributes *pConfig = NULL;
IMFActivate **ppDevices = NULL;
// Create an attribute store to hold the search criteria.
HRESULT hr = MFCreateAttributes(&pConfig, 1);
// Request video capture devices.
if (SUCCEEDED(hr))
{
hr = pConfig->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
}
// Enumerate the devices,
if (SUCCEEDED(hr))
{
hr = MFEnumDeviceSources(pConfig, &ppDevices, &count);
}
// Create a media source for the first device in the list.
if (SUCCEEDED(hr))
{
if (count > 0)
{
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
}
else
{
hr = MF_E_NOT_FOUND;
}
}
for (DWORD i = 0; i < count; i++)
{
ppDevices[i]->Release();
}
CoTaskMemFree(ppDevices);
return hr;
}
可以查询各种属性的激活对象,包括:
- MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME 属性包含设备的显示名称。 显示名称适用于向用户显示,但可能不是唯一的。
- 对于视频设备,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK 属性包含指向设备的符号链接。 符号链接唯一标识系统上的设备,但不是可读字符串。
- 对于音频设备,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID 属性包含设备的音频终结点 ID。 音频终结点 ID 类似于符号链接。 它唯一标识系统上的设备,但不是可读字符串。
以下示例采用 IMFActivate 指针的数组,并将每个设备的显示名称打印到调试窗口:
void DebugShowDeviceNames(IMFActivate **ppDevices, UINT count)
{
for (DWORD i = 0; i < count; i++)
{
HRESULT hr = S_OK;
WCHAR *szFriendlyName = NULL;
// Try to get the display name.
UINT32 cchName;
hr = ppDevices[i]->GetAllocatedString(
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
&szFriendlyName, &cchName);
if (SUCCEEDED(hr))
{
OutputDebugString(szFriendlyName);
OutputDebugString(L"\n");
}
CoTaskMemFree(szFriendlyName);
}
}
如果已知道视频设备的符号链接,可通过另一种方法为设备创建媒体源:
- 调用 MFCreateAttributes 来创建属性存储。
- 将 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 属性设置为 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID。
- 将 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK 属性设置为符号链接。
- 调用 MFCreateDeviceSource 或 MFCreateDeviceSourceActivate 函数。 前者返回 IMFMediaSource 指针。 后者返回指向激活对象的 IMFActivate 指针。 可以使用激活对象创建源。 (可以将激活对象封送到另一个进程,因此,如果要在另一个进程中创建源,则它很有用。有关详细信息,请参阅 激活对象。)
以下示例采用视频设备的符号链接并创建媒体源。
HRESULT CreateVideoCaptureDevice(PCWSTR *pszSymbolicLink, IMFMediaSource **ppSource)
{
*ppSource = NULL;
IMFAttributes *pAttributes = NULL;
IMFMediaSource *pSource = NULL;
HRESULT hr = MFCreateAttributes(&pAttributes, 2);
// Set the device type to video.
if (SUCCEEDED(hr))
{
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
}
// Set the symbolic link.
if (SUCCEEDED(hr))
{
hr = pAttributes->SetString(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
(LPCWSTR)pszSymbolicLink
);
}
if (SUCCEEDED(hr))
{
hr = MFCreateDeviceSource(pAttributes, ppSource);
}
SafeRelease(&pAttributes);
return hr;
}
有一种从音频终结点 ID 创建音频设备的等效方法:
- 调用 MFCreateAttributes 来创建属性存储。
- 将 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 属性设置为 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID。
- 将 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID 属性设置为终结点 ID。
- 调用 MFCreateDeviceSource 或 MFCreateDeviceSourceActivate 函数。
以下示例采用音频终结点 ID 并创建媒体源。
HRESULT CreateAudioCaptureDevice(PCWSTR *pszEndPointID, IMFMediaSource **ppSource)
{
*ppSource = NULL;
IMFAttributes *pAttributes = NULL;
IMFMediaSource *pSource = NULL;
HRESULT hr = MFCreateAttributes(&pAttributes, 2);
// Set the device type to audio.
if (SUCCEEDED(hr))
{
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID
);
}
// Set the endpoint ID.
if (SUCCEEDED(hr))
{
hr = pAttributes->SetString(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID,
(LPCWSTR)pszEndPointID
);
}
if (SUCCEEDED(hr))
{
hr = MFCreateDeviceSource(pAttributes, ppSource);
}
SafeRelease(&pAttributes);
return hr;
}
使用捕获设备
为捕获设备创建媒体源后,请使用 源读取器 从设备获取数据。 源阅读器提供包含捕获音频数据或视频帧的媒体示例。 下一步取决于应用程序方案:
如果要将音频捕获与视频捕获相结合,请使用 聚合媒体源。 聚合媒体源包含媒体源的集合,并将其所有流合并到单个媒体源对象中。 若要创建聚合媒体源的实例,请调用 MFCreateAggregateSource 函数。
关闭捕获设备
不再需要捕获设备时,必须通过调用 MFCreateDeviceSource 或 IMFActivate::ActivateObject在 IMFMediaSource 对象上调用 关闭 来关闭设备。 未能调用 关闭 可能会导致内存泄漏,因为系统可能会保留对 IMFMediaSource 资源的引用,直到调用 关闭。
if (g_pSource)
{
g_pSource->Shutdown();
g_pSource->Release();
g_pSource = NULL;
}
如果分配了包含捕获设备的符号链接的字符串,则还应释放此对象。
CoTaskMemFree(g_pwszSymbolicLink);
g_pwszSymbolicLink = NULL;
g_cchSymbolicLink = 0;
相关主题