DirectShow - 无法创建新线程

时间:2011-01-20 20:11:29

标签: c++ mfc directshow beginthreadex

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

首先要介绍几件事:

  1. 该图的目的是从具有暴露的DirectShow接口的FrameGrabber中提取原始视频。该图通过VMR9显示正确的视频,并通过ISampleGrabber(DirectShow示例)将原始帧暴露给某些算法。
  2. 图表已在单个项目中成功构建并运行。视频显示得很好,一切都很开心。
  3. 现在,当我将其集成到现有代码中时会出现问题。从应用程序的初始化开始,我首先创建并启动图形,以无窗口模式运行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); 
        }
    }
    

    值得注意的是,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);
    

3 个答案:

答案 0 :(得分:2)

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

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

更新:无论我发现有关具体错误的内容,您都会收到有关内存泄漏的提示。请注意,只有420MB(如您所述)可能已提交,但更多页面可能已保留,这些页面仍会计入应用程序的2GB虚拟空间限制。运行DirectShow图可能已经用完了这个空间的剩余部分。

因此,DirectShow本身很可能不是错误的原因,而是恰好揭示了应用程序中的现有错误。

以下是MSDN中可能与您相关的一些其他信息,特别是如果您在程序中先前创建了其他线程(Thread Stack Size):

  

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

答案 1 :(得分: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

希望这会对你有所帮助。

答案 2 :(得分:0)

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

FWIW。