我正在使用其 SDK 从 DVR 接收 H.264 流
。存在内存泄漏,我认为是 SDK 导致了所有泄漏。但是当我录制流并从磁盘读取一帧一帧播放时(不涉及任何第 3 方 dll),我注意到问题不在于 dll,而是流本身。
奇怪的是,DivX H264 解码器
是唯一不会导致内存泄漏的编解码器,但当流运行很长时间时,有时 DivX 解码器也会崩溃。我更喜欢使用 Microsoft DTV-DVD 视频解码器
,但它会导致大量内存泄漏并丢掉大量帧。我尝试过的许多其他 H.264 解码器的行为方式相同。
我使用一些 h.264 解析器
检查了 h.264 帧
并与其他一些无问题的流进行了比较,但我没有从日志中注意到任何明显的东西。
由于我的问题是关于 h.264 帧结构,我准备了一个名为 FramesFromFileSourceFilter
的源过滤器,您可以在下面下载它。
http://www.akaydin.com/directshow/FramesFromFileSourceFilter.zip
这是一个 Visual Studio 2008
项目,所有依赖项都包含在 zip 文件中相对位置的文件夹中(包括 h.264 帧)。因此,您需要做的就是编译项目,使用 regsvr32.exe
注册输出,并使用您想要的来自 GraphEdit 或 GraphStudio 的任何 h.264 解码器运行过滤器。示例图如下。
h264 帧也可以作为单个原始 h264 文件在下面的链接中使用,可以通过 VLC 播放(FPS 错误,因为原始帧是 12 FPS)。
http://www.akaydin.com/directshow/stream.zip
问题:
除 DivX 解码器外,许多著名的 H264 解码器可能会导致内存泄漏问题。这个流有什么问题?
更新 1
读取数据线程已删除,功能移至 FillBuffer 中,无需使用任何缓冲区和标志。问题还是一样。
http://www.akaydin.com/directshow/FramesFromFileSourceFilterUpdate1.zip
更新 2
Update1 在 FillBuffer()
函数中使用了 Sleep()
,这导致了一些问题。现在我删除了 Sleep()
并使用 SetTime()
获得了 ~12 FPS。这也解决了 Microsoft DTV-DVD Video Decoder
的丢帧问题,但没有解决内存问题。
http://www.akaydin.com/directshow/FramesFromFileSourceFilterUpdate2.zip
内存增加仅发生在 Working Set
中。 Virtual Bytes
和 Private Bytes
似乎是稳定的。什么可能导致连续的 Working Set
内存递增,而这只会发生在 Microsoft DTV-DVD Video Decoder
上?
最佳答案
你不对你的变量做任何同步
BYTE* m_buffer;
DWORD m_bufferSize;
bool isFrameReady;
它们被两个并发线程使用。您只是通过这种不准确的分配/解除分配和/或让您的代码因访问冲突而崩溃而泄漏了您的内存。 DLL 的调试版本通过在您运行测试时向您显示“堆损坏”警报来指示这一点。运行时行为可能因解码器和环境而异,但这绝对是一个需要修复的严重错误。
例如,您可以在填充缓冲区的线程中使用 CAutoLock cAutoLock(m_pLock);
以防止在从文件读取数据时访问流式线程。
请注意,您将下一帧读入同一个缓冲区指针,而没有检查之前分配的内存是否已释放,您只是覆盖了指针,可能会留下泄漏。
内存泄漏/工作集更新:现在,当代码问题得到解决后,不需要的运行时行为是Working Set
大小的增加。这不是泄漏。这表明 Windows 将该进程视为一种优先级(为什么不呢?它是事件的并且使用内存)并向该进程抛出更多实际页面以促进其性能。参见 this answer关于进程内存指标如何对应于应用程序中的内存泄漏的良好解释。
您可能看到的解码器之间的差异可能是由于某些解码器适用于较小数量的缓冲区,或者更积极地重用它们,例如更喜欢从池中取出相同的缓冲区,而不是从所有可用缓冲区中一个一个地挑选。
关于video - 某些解码器的 H.264 帧内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11086415/