3

我在将 DirectShow 图形集成到现有应用程序中时遇到了一些奇怪的问题。

首先要介绍几件事:

  1. 该图的目的是从具有暴露 DirectShow 接口的 FrameGrabber 中获取原始视频。该图通过 VMR9 将视频正确显示,并通过 ISampleGrabber(DirectShow 示例)将原始帧暴露给某些算法。
  2. 该图已在单个项目中成功构建并运行。视频显示良好,一切都很愉快。

现在,当我将其集成到现有代码中时,问题就出现了。从应用程序的初始化开始,我首先创建并启动图形,在无窗口模式下运行 VMR9。在初始化的后期,我通过 _beginthreadex 创建了几个工作线程。当且仅当图形已构建并运行时,对 _beginthreadex 的调用失败并返回代码 12(内存不足)。

现在显而易见的答案是我内存不足或可能是其他一些资源。但是,当线程尝试启动时,我正在使用约 420MB 的 2GB 系统内存。线程堆栈大小已明确设置为 1MB。所以据我所知,我并没有失忆。此外,正在运行的应用程序中总共有 15 个线程,所以我并没有创造一个荒谬的数量。

有没有人遇到过与 DirectShow 类似的问题?我正在寻找任何输入,我们已经尝试调试这个问题很长一段时间了,但一直没有成功。

我将发布您需要的任何代码,与大多数 DirectShow 图表一样,代码很长。

编辑

按照要求。我不确定 DirectShow 代码的哪一部分导致线程无法启动。但是,如果我只构建而不运行图表,则线程可以正常工作。所以我猜想失败发生在运行调用之后。我运行图表的代码如下:

    if (CurrentState != Stopped)
        return WrongState;

    HRESULT hr;
    printf("Attempting to run graph... ");
    Timer->Start();
    hr = pMediaControl->Run();
    if (FAILED(hr))
    {
        OAFilterState State;
        hr = pMediaControl->GetState(1000, &State);     
        if ((SUCCEEDED(hr) && State != State_Running) || FAILED(hr))
        {
            return FailedToStartGraph;
        }
    }
    CurrentState = Streaming;
    SetVMRSize();
    Timer->Stop();
    RunTime->Start();
    FrameRate->Reset();

    return NoError;

SetVMRSize 函数只是将 VMR 调整为其父窗口的大小:

void KontronGraph::SetVMRSize()
{
    if (CurrentState == Disconnected || VideoMode != ParentWindow)
        return;
    long lWidth, lHeight; 
    HRESULT hr = pWindowController->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL); 
    if (SUCCEEDED(hr))
    {
        RECT rcSrc, rcDest; 
        // Set the source rectangle.
        rcSrc.left = 0;
        rcSrc.right = lWidth;
        rcSrc.top = 0;
        rcSrc.bottom = lHeight;

        // Get the window client area.
        GetClientRect(MyHwnd, &rcDest); 
        // Set the destination rectangle.
        rcDest.right = rcDest.right - rcDest.left;
        rcDest.bottom = rcDest.bottom - rcDest.top;
        rcDest.left = 0;
        rcDest.top = 0;

        // Set the video position.
        hr = pWindowController->SetVideoPosition(&rcSrc, &rcDest); 
    }
}

值得注意的是,pWindowControllerIVMRWindowlessControl9和 pMediaControl 是IMediaControl

编辑 2

使用 CreateThread 而不是 __beginthreadex 测试了代码。启动线程失败后,GetLastError() 返回:

8:没有足够的存储空间来处理这个命令。

创建线程的代码如下所示:

HANDLE worker_thread = CreateThread(0, 
Thread_Stack_Size, worker_thread_op, thread_param, 0, 0);

CreateThread 的一些参数:

Thread_Stack_Size = 1024 * 1024;
typedef DWORD (WINAPI *worker_thread_op_type)(LPVOID params);
4

3 回答 3

2

首先,我建议您替换_beginthreadexCreateThread然后使用GetLastError来确定任何错误的原因,这通常比设置的 CRT 错误代码更具体_beginthreadex。让我知道您通过这样做观察到的情况,我会更新我的答案。

另外,您能否发布导致线程创建失败的(DirectShow)代码部分以及创建线程的代码行?

更新:无论我能找到关于特定错误的任何信息,您都会得到关于可能的内存泄漏的提示。请注意,只有 420MB(如您提到的)可能会被提交,但可能会保留更多页面,并且这些页面仍然计入应用程序的 2GB 虚拟空间限制。运行 DirectShow 图形可能已用完该空间的剩余部分。

因此,DirectShow 本身很可能不是错误的原因,而是碰巧揭示了您的应用程序中存在的错误。

以下是 MSDN 中可能与您相关的一些附加信息,特别是如果您在程序的早期创建了其他线程(线程堆栈大小):

每个新线程都会收到自己的堆栈空间,包括保留的和最初提交的内存。保留内存大小表示虚拟内存中的总堆栈分配。因此,保留大小仅限于虚拟地址范围。最初提交的页面在被引用之前不会使用物理内存;...当线程退出时释放堆栈。如果线程被另一个线程终止,它不会被释放。

于 2011-01-24T17:34:22.493 回答
0

在 sysinternals-web-pages 上有许多视频处理如何使用内存以及由谁使用。可能这些可以帮助您解决问题。

http://technet.microsoft.com/en-us/sysinternals/bb963887

http://player.microsoftpdc.com/Session/1689962d-dea2-48bd-80d8-96e954fa5329

http://player.microsoftpdc.com/Session/1c97b279-d7e3-4a3e-9a76-0dac23dfddb5

希望这会帮助你。

于 2011-01-25T16:25:29.703 回答
0

从您的解释中我并不能完全清楚这是否是一个问题,但是对于大多数 DirectX 相关工具(我假设包括 DirectShow),您需要确保所有相关调用都发生在同一个线程上;换句话说,如果您在给定线程上设置 DirectShow,请使用同一线程对其进行所有调用。自从我使用 DirectShow 已经很长时间了,所以我不是 100% 肯定这适用,但它确实解决了 D3D 的许多问题,这是一项密切相关的技术。

FWIW。

于 2011-01-31T17:05:54.723 回答