DirectShow - 无法创建新线程
我在将 DirectShow 图形集成到现有应用程序中时遇到一些奇怪的问题。
首先要介绍几件事:
- 该图的目的是从具有公开的 DirectShow 接口的 FrameGrabber 获取原始视频。该图通过 VMR9 正确显示视频,并通过 ISampleGrabber(DirectShow 示例)将原始帧暴露给某些算法。
- 该图已在单个项目中成功构建并运行。视频显示正常,一切都很愉快。
现在,当我将其集成到现有代码中时,问题就出现了。从应用程序的初始化开始,我首先创建并启动图表,在无窗口模式下运行 VMR9。稍后在初始化中,我通过 _beginthreadex 创建了几个工作线程。当且仅当图形已构建并运行时,对 _beginthreadex 的调用会失败,返回代码为 12(内存不足)。
现在显而易见的答案是我内存不足或其他资源不足。然而,当线程尝试启动时,我使用了约 420MB 的 2GB 系统内存。线程堆栈大小已明确设置为 1MB。所以据我所知,我并没有失去记忆。此外,正在运行的应用程序中总共有 15 个线程,因此我不会创建一个荒谬的数量。
有人在 DirectShow 上遇到过类似的问题吗?我正在寻找任何意见,我们已经尝试调试这个问题很长一段时间了,但还没有成功。
我将发布您需要的任何代码,与大多数 DirectShow 图形一样,代码很长。
编辑
根据要求 。我不确定 DirectShow 代码的哪一部分导致线程无法启动。但是,如果我只构建而不运行图表,则线程可以正常工作。所以我猜测故障发生在 run 调用之后。我运行该图的代码如下:
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
Edit 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);
I am having some strange issues integrating a DirectShow graph into an existing application.
A couple things to cover first:
- 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).
- 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);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,我建议您将
_beginthreadex
替换为CreateThread
,然后使用GetLastError
确定任何错误的原因,这通常比 CRT 错误代码集更具体通过_beginthreadex
。让我知道你通过这样做观察到了什么,我会更新我的答案。另外,您能否发布导致线程创建失败的(DirectShow)代码部分,以及创建线程的代码行?
更新:无论我能找到关于特定错误的信息,您都会得到可能存在内存泄漏的提示。请注意,可能仅提交 420MB(如您所提到的),但可能保留更多页面,并且这些页面仍计入应用程序的 2GB 虚拟空间限制。运行 DirectShow 图形可能会耗尽该空间的剩余空间。
因此,DirectShow 本身很可能不是错误的原因,而是碰巧揭示了应用程序中现有的错误。
以下是来自 MSDN 的一些可能与您相关的附加信息,特别是如果您之前在程序中创建了其他线程 (线程堆栈大小):
To start with, I would suggest that you replace
_beginthreadex
withCreateThread
and then useGetLastError
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):
在 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
希望这会对您有所帮助。
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.
从您的解释中我并不完全清楚这是否是一个问题,但对于大多数 DirectX 相关工具(我假设包括 DirectShow),您需要确保所有相关调用都发生在同一线程上;换句话说,如果您在给定线程上设置 DirectShow,则使用同一线程对其进行所有调用。我已经很久没有使用 DirectShow 了,所以我不能 100% 肯定它是否适用,但它确实解决了 D3D 的很多问题,D3D 是一项密切相关的技术。
FWIW。
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.