DirectShow - Unable to create new threads

1.1k Views Asked by At

I am having some strange issues integrating a DirectShow graph into an existing application.

A couple things to cover first:

  1. The graph's purpose is to bring raw video from a FrameGrabber which has an exposed DirectShow interface. The graph takes the video right to display through VMR9 as well as exposing the raw frames to some algorithms through the ISampleGrabber (DirectShow Examples).
  2. The graph has been built and run succesfully in an individual project. The video is displayed fine and everything is happy.

Now the issue comes in when I am integrating this into existing code. From the initialization of the application I first create and start the graph, running VMR9 in a windowless mode. Later in the initialization I create a couple of worker threads via _beginthreadex. The calls to _beginthreadex fail with a return code of 12 (Out of memory) when and ONLY when the graph has both been built and ran.

Now the obvious answer is I am out of memory or perhaps some other resource. However, at the point when the threads are trying to start I am using ~420MB of the 2GB system memory. The thread stack size has been explicitly set to 1MB. So I am not out of memory as far as I can tell. Additionally, there are a total of 15 threads in the running application so I am not creating an absurd amount.

Has anyone had/experienced a similar issue with DirectShow? I am looking for any input at all, we have been trying to debug this issue for quite some time now and have not been succesful.

I will post any code that you require, as with most DirectShow graphs the code is lengthy.

Edit

As requested. I'm not sure what part of the DirectShow code causes the threads to fail to launch. However, if I only build, but do not run the graph, the threads work alright. So I would guess that the failure occurs after the run call. My code to run the graph is as follows:

    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;

The SetVMRSize function simply resizes the VMR to its parent window:

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

Of note, pWindowController is IVMRWindowlessControl9 and pMediaControl is IMediaControl

Edit 2

Tested the code using CreateThread instead of __beginthreadex. After failing to launch the threads, GetLastError() returns:

8 : Not enough storage is available to process this command.

The code to create threads looks like:

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

Some of the parameters for CreateThread:

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

There are 3 best solutions below

0
On

At the sysinternals-web-pages there are a number of video's that deal with how memory is used and by whom. May be thse can help you with your problem.

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

Hope this will help you.

2
On

To start with, I would suggest that you replace _beginthreadex with CreateThread and then use GetLastError to determine the cause of any error, which is often more specific than the CRT error codes set by _beginthreadex. Let me know what you observe by doing this and I'll update my answer.

Also, can you post the portion of your (DirectShow) code that causes the thread creation to fail, as well as the lines of code that create the thread?

Update: Whatever I could find regarding the specific error you're getting hints towards a possible memory leak. Note that only 420MB (as you mentioned) may be committed but more pages could have been reserved and these pages still count towards the 2GB virtual space limit of your application. Running the DirectShow graph might have used up whatever remains of this space.

So it is most likely that DirectShow itself isn't the cause of the error, but instead happened to reveal an existing error in your application.

Here's some additional information from MSDN that might be relevant to you, especially if you created other threads earlier in your program (Thread Stack Size):

Each new thread receives its own stack space consisting of both reserved and initially committed memory. The reserved memory size represents the total stack allocation in virtual memory. As such, the reserved size is limited to the virtual address range. The initially committed pages do not utilize physical memory until they are referenced; ... A stack is freed when its thread exits. It is not freed if the thread is terminated by another thread.

1
On

I'm not totally clear from your explanation if this is an issue or not, but with most DirectX related tools (which I assume includes DirectShow) you need to make sure that all of your related calls occur on the same thread; in other words, if you set up DirectShow on a given thread, do all of your calls to it using that same thread. It's been a long time since I used DirectShow so I'm not 100% positive that this applies, but it definitely solves a lot of issues with D3D, which is a closely related technology.

FWIW.