Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Media extensions sample演示了如何在windows store应用程序中实现和使用media foundation (MF)过滤器,这对想要实现自己的播放器软件的开发者来说很有参考意义。但是这个示例代码有一个问题,当视频停止播放的时候不会调用CMPEG1Source的析构函数,这样就会导致内存泄露。
实际上这个问题是由于MF过滤器中的COM对象的引用计数没有匹配导致的。当MediaElement对象的source设为null的时候,CMPEG1Source对象的引用计数并没有减为0,这就导致了CMPEG1Source对象无法及时释放。
如果我们检查CMPEG1Source对象的引用计数,我们会发现在CMPEG1Stream的构造函数中会增加CMPEG1Source对象的引用计数:
CMPEG1Stream::CMPEG1Stream(CMPEG1Source *pSource, IMFStreamDescriptor *pSD, HRESULT& hr) :
m_cRef(1),
m_pEventQueue(NULL),
m_state(STATE_STOPPED),
m_bActive(FALSE),
m_bEOS(FALSE),
m_flRate(1.0f)
{
…
m_pSource = pSource;
m_pSource->AddRef();
…
}
这个引用计数会在CMPEG1Stream的析构函数中被减去:
CMPEG1Stream::~CMPEG1Stream()
{
assert(m_state == STATE_SHUTDOWN);
SafeRelease(&m_pSource);
…
}
但是CMPEG1Stream的析构函数也没有被调用到,这就意味着实际上CMPEG1Stream对象也存在着内存泄露。
那么,让我们再来检查一下 CMPEG1Stream对象的引用计数。当我们在StreamList对象的AddStream函数中增加一个stream的时候,CMPEG1Stream的引用计数会加1:
HRESULT AddStream(BYTE id, CMPEG1Stream *pStream)
{
…
m_streams[m_count] = pStream;
pStream->AddRef();
…
}
然后CMPEG1Stream的引用计数会在StreamList的Clear函数中减1:
void Clear()
{
for (UINT32 i = 0; i < MAX_STREAMS; i++)
{
SafeRelease(&m_streams[i]);
}
m_count = 0;
}
不幸的是,当我们关闭CMPEG1Source对象时,StreamList的Clear函数并没有被调用到。所以解决方案就是我们需要在CMPEG1Source::Shutdown函数中加上一行来清除StreamList中CMPEG1Stream对象的引用计数:
HRESULT CMPEG1Source::Shutdown()
{
…
if (SUCCEEDED(hr))
{
// Shut down the stream objects.
for (DWORD i = 0; i < m_streams.GetCount(); i++)
{
(void)m_streams[i]->Shutdown();
}
m_streams.Clear();
…
}
…
}
当我们再Shutdown函数中加上了m_streams.Clear()这一行以后,这个内存泄露问题就得到解决了,示例程序也能够正常工作了。