DirectShow - 无法创建新线程

3
我正在将一个DirectShow图形集成到一个现有应用程序中,但遇到了一些奇怪的问题。
首先需要说明以下几点:
1. 该图的目的是从具有公开DirectShow接口的FrameGrabber中获取原始视频。该图通过VMR9直接将视频显示出来,并通过ISampleGrabber(DirectShow示例)将原始帧暴露给一些算法。 2. 该图已经在单独的项目中构建并成功运行。视频正常显示,一切都很顺利。
现在的问题是当我将其集成到现有代码中时出现了问题。在初始化应用程序时,我首先创建并启动图形,以无窗口模式运行VMR9。稍后在初始化时,我通过_beginthreadex创建了一些工作线程。只有当构建并运行图形时,调用_beginthreadex才会返回12(内存不足)错误码。
显然,答案是我没有足够的内存或其他资源。然而,在线程尝试启动的时候,我使用了2GB系统内存的约420MB。线程堆栈大小已明确设置为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); 
    }
}

需要注意的是,pWindowController是IVMRWindowlessControl9,而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);

你是否可能在使用你的显存? - StefanE
3个回答

2
首先,我建议您使用CreateThread替换_beginthreadex,然后使用GetLastError确定任何错误的原因,这通常比_beginthreadex设置的CRT错误代码更具体。请告诉我您通过此操作观察到的情况,我会更新我的答案。
另外,请问您能否发布导致线程创建失败的(DirectShow)代码部分以及创建线程的代码行?
更新:我找到的关于您收到的特定错误的所有信息都提示可能存在内存泄漏。请注意,只有420MB(如您所述)可能被“提交”,但更多页面可能已经被“保留”,这些页面仍然计入应用程序2GB虚拟空间限制。运行DirectShow图表可能已经使用了剩余空间。
因此,DirectShow本身很可能不是错误的原因,而是偶然暴露了应用程序中现有错误。
以下是来自MSDN的一些额外信息,这对您可能很相关,特别是如果您在程序中早期创建了其他线程(线程堆栈大小):
每个新线程都接收其自己的堆栈空间,其中包括保留和最初分配的内存。保留内存大小表示虚拟内存中的总堆栈分配。因此,保留大小受虚拟地址范围的限制。最初提交的页面在被引用之前不使用物理内存;……当线程退出时,堆栈将被释放。如果线程由另一个线程终止,则不会释放它。

已添加Directshow代码,一旦测试完成,将添加有关CreateThread的注释。 - DeusAduro
我已经添加了CreateThread测试的结果。此外,DirectShow图形位于与主应用程序分开的单独的DLL中。我不确定这是否会增加问题,但我认为值得一提。 - DeusAduro

0

从你的解释中我并不完全清楚这是否是一个问题,但对于大多数与DirectX相关的工具(我假设包括DirectShow),你需要确保所有相关的调用发生在同一个线程上;换句话说,如果你在给定的线程上设置了DirectShow,请使用相同的线程进行所有调用。我已经很久没有使用DirectShow了,所以我不能百分之百确定这是否适用,但它绝对可以解决许多与D3D有关的问题,因为它们是密切相关的技术。

顺便说一下。


嗨,我相信这适用于DirectShow,但是我已经在做这个了(所有DS调用都在创建它的同一线程中)。不过还是谢谢你的建议。 - DeusAduro

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接