1

我的任务是创建一个应用程序,该应用程序接受音频/视频捕获输入(使用 Elgato Cam Link)并将其输出回用户。根据 Microsoft 的Audio/Video Capture in Media Foundation文档,它建议“如果要将音频捕获与视频捕获结合起来,请使用聚合媒体源。

我从 topoedit 的源代码中提取了我需要的大部分代码,但是 topoedit 没有在任何地方使用聚合源,所以在正确使用它们时我有点盲目。

使用聚合媒体源时,我遇到了两个不同的问题。

  1. 帧速率
    当我使用聚合媒体源时,我有一个捕获设备 (Elgato Cam Link) 可以成功播放音频和视频,但由于某种原因,帧速率比我只运行两个完全独立的拓扑(一个用于视频,一个用于音频)。

  2. 调用 IMFTopoloader::Load() 时出现错误 MF_E_TOPO_CODEC_NOT_FOUND (0xC00D5212)
    当我尝试在两台不同的笔记本电脑上使用聚合媒体源(使用任何内置的网络摄像头/麦克风组合)时,我遇到了这个错误。这个错误让我感到困惑,因为如果我使用两个完全独立的拓扑(一个用于视频,一个用于音频),它运行得很好。

主要设置:

  • 操作系统:Windows 10
  • 采集设备:Elgato Cam Link(带有 HDMI 输入的 USB 记忆棒)
  • 语言:C++

只是为了提前排除一些建议......

  • 只需使用 DirectShow!
    我希望我能。我负责这个任务的唯一原因是因为我们的 DirectShow 解决方案在 Elgato Cam Link 设备上存在严重的帧速率问题。我们无法弄清楚原因,所以媒体基金会似乎是我们最好的选择。

  • 使用两个独立的拓扑!
    这就是我目前的工作方式。只是感觉不对劲,你知道吗?文档说要使用聚合源,所以我想做我的尽职调查。最后,如果我没有得到这个问题的答案,我至少可以高枕无忧,因为我知道我有一些功能,但我主要是问这个问题,以防我能做得更好。Skype必须做这样的事情吗?(再想一想,Skype 不会将您的音频输出回您自己的扬声器,所以也许不是)肯定有人知道如何使用聚合源。

鉴于我的程序在 Elgato 设备上成功运行,我怀疑我没有做任何可怕的错误。如果有问题,可能是我没有的代码,而不是我能展示的任何东西。

话虽如此,这就是我创建聚合源的地方(为简洁起见,不包括错误检查)。

HRESULT GenerateAggregateSource(IMFMediaSource*& pAggSource, IMFMediaSource* pSource1, IMFMediaSource* pSource2)
{
    pAggSource = NULL;

    HRESULT hr = S_OK;

    IMFCollection* pSourceCollection = NULL;
    hr = ::MFCreateCollection(&pSourceCollection);

    hr = pSourceCollection->AddElement(pSource1);

    hr = pSourceCollection->AddElement(pSource2);

    hr = ::MFCreateAggregateSource(pSourceCollection, &pAggSource);
    pSourceCollection->Release();   // Done with this

    return hr;
}

稍后我将 EVR 连接到流描述符 0,将 SAR 连接到流描述符 1。

如果您更热衷于解决问题 2(再次,为简洁起见,不包括错误检查),我将这里称为 IMFTopoloader::Load()。

HRESULT ResolveTopology(IMFTopology*& pTopology, IMFMediaSession* pMediaSession)
{
    HRESULT hr = S_OK;

    IMFTopoLoader* pTopoLoader = NULL;
    hr = ::MFCreateTopoLoader(&pTopoLoader);

    IMFTopology* pFullTopology = NULL;
    hr = pTopoLoader->Load(pTopology, &pFullTopology, NULL);
    // Laptop webcams seem to encounter this error here
    //MF_E_TOPO_CODEC_NOT_FOUND

    hr = pMediaSession->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, pFullTopology);

    // Swap the topology we're holding
    pTopology->Release();
    pTopology = pFullTopology;

    // Done with this
    pTopoLoader->Release();

    return hr;
}

使用请求的拓扑更新:

这是我的部分拓扑的粗略示例。这可能是您所期望的,因为我不想做任何花哨的事情。

                 ⇗ EVR
Agg. Source (A/V)
                 ⇘ SAR

一旦我解决了拓扑,注入了哪些额外的东西?我不确定如何走链并查询当时拓扑中的所有内容。如果您相信 topoedit 分别对音频和视频源所做的事情,那么它看起来像这样。

                 ⇗ {CF862982-23B0-4E3D-8C76-D03FEF084AF8} ⇒ EVR
Agg. Source (A/V)
                 ⇘ SAR

是什么{CF862982-23B0-4E3D-8C76-D03FEF084AF8}?我不确定,也不知道如何找到。

当我再次访问 Elgato 时,我将更新上述拓扑。我目前没有拥有它。

更新 2写这篇文章的客户似乎并不关心向我提供任何反馈(好或坏),所以我不太关心跟进这个奇怪的问题。

4

0 回答 0