【MediaFoundation】读取音视频

原文链接: 官方文档

Microsoft Media Foundation支持音频和视频捕获。视频捕获设备通过UVC类驱动程序支持,并必须与UVC 1.1兼容。音频捕获设备通过Windows音频会话API(WASAPI)支持。

在Media Foundation中,捕获设备通过媒体源对象来表示,该对象公开了IMFMediaSource接口。在大多数情况下,应用程序不会直接使用这个接口,而是会使用一个更高级的API,如Source Reader,来控制捕获设备。

枚举音视频捕获设备

要枚举系统上的捕获设备,请执行以下步骤:

  1. 调用MFCreateAttributes函数来创建一个属性存储。
  2. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE属性设置为以下值之一:
描述
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID 列举音频设别
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID 列举视频设别
  1. 调用MFEnumDeviceSources函数。该函数分配了一个IMFActivate指针的数组。每个指针表示系统上一个设备的激活对象。
  2. 调用IMFActivate::ActivateObject 方法从一个激活的对象中创建一个媒体源的实例。
  3. 可以访问被激活的对象的属性,包括:
    • MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME 包含设备展示的名字。这个展示的名字是给用户看的,并不一定是唯一的。
    • 对于视频设备,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK 属性包含了设备的符号链接。符号链接在系统上唯一标识设备,但不是可读的字符串。
    • 对于音频设备, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID 效果同上。

下面是一个完整的Demo用于输出视频设备的名称。

#include 
#include 
#include 
#include 
#include 
#include 
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfplat.lib")


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");*/

            // 直接输出到终端
            std::wcout << szFriendlyName << std::endl;
        }
        CoTaskMemFree(szFriendlyName);
    }
}

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);
        DebugShowDeviceNames(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;
}

int main()
{
    IMFMediaSource* ppSource = nullptr;
    auto ret = CreateVideoCaptureDevice(&ppSource);
}

使用捕获设备

在为捕获设备创建媒体源后,使用 Source Reader 从设备获取数据。Source Reader 提供包含捕获音频数据或视频帧的媒体样本。下一步取决于你的应用场景:

  • 视频预览:使用 Microsoft Direct3D 或 Direct2D 来显示视频
  • 文件捕获:使用 Sink Writer 对文件进行编码
  • 音频预览: Use WASAPI.

如果你想将音频捕获与视频捕获结合起来,可以使用聚合媒体源。聚合媒体源包含一组媒体源,并将所有的流合并到一个单一的媒体源对象中。要创建聚合媒体源的实例,调用 MFCreateAggregateSource 函数。

关闭设备

当不再需要捕获设备时,你必须通过调用 MFCreateDeviceSource 或 IMFActivate::ActivateObject 获取的 IMFMediaSource 对象上调用 Shutdown 来关闭设备。如果不调用 Shutdown,可能会导致内存链接,因为系统可能会保持对 IMFMediaSource 资源的引用,直到调用 Shutdown 为止。

if (g_pSource)
{
    g_pSource->Shutdown();
    g_pSource->Release();
    g_pSource = NULL;
}

如果申请了字符容器或者符号链接设别,你应该释放这些对象

   CoTaskMemFree(g_pwszSymbolicLink);
    g_pwszSymbolicLink = NULL;
    g_cchSymbolicLink = 0;

你可能感兴趣的:(Audio,音视频)