视频录制在 IMFSinkWriter->Finalize() 上挂起;

Video Recording Hangs on IMFSinkWriter->Finalize();

我在使用 Media Foundation 将视频录制完成为 .mp4 时遇到问题,其中对 IMFSinkWriter->Finalize(); 的调用永远挂起。它并不总是发生,并且几乎可以在任何机器上发生(在 Windows 服务器、7、8、10 上看到)。 Flush() 事先在音频和视频流上调用,并且在 FlushFinalize 之间没有添加新样本。关于什么可能导致 Finalize 永远挂起的任何想法?

我尝试过的事情:

Everything comes back as S_OK, not seeing any issues

Haven't been able to reproduce since adding this but this would give the best information about what's going on when I get it working.

Didn't find many samples and it looks like my code is similar to the ones that were found

Encoders varied between AMD H.264 Hardware MFT Encoder and H264 Encoder MFT on machines that could reproduce the issue. Versions didn't seem to matter and some of the machines were up to date with video drivers.

这里有一些代码示例,没有任何 HRESULT 检查(代码量增加了一倍,所以我把它拿出来了)

构建接收器示例:

CComPtr<IMFAttributes> pAttr;
::MFCreateAttributes( &pAttr, 4 );
pAttr->SetGUID( MF_TRANSCODE_CONTAINERTYPE, GetFileContainerType() );
pAttr->SetUINT32( MF_LOW_LATENCY, FALSE ); // Allows better multithreading
pAttr->SetUINT32( MF_SINK_WRITER_DISABLE_THROTTLING, TRUE ); // Does not block
pAttr->SetUINT32( MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE );

m_pCallback.Attach( new MFSinkWriterCallback() );
pAttr->SetUnknown( MF_SINK_WRITER_ASYNC_CALLBACK, m_pCallback );

::MFCreateSinkWriterFromURL( m_strFilename.c_str(), NULL, pAttr, &m_pSink );

if ( m_pVideoInputType && m_pVideoOutputType )
{
   m_pSink->AddStream( m_pVideoOutputType, &m_dwVideoStreamId );
   // Attributes for encoding?
   CComPtr<IMFAttributes> pAttrVideo;

   // Not sure if these are needed
   //::MFCreateAttributes( &pAttrVideo, 5 );

   m_pSink->SetInputMediaType( m_dwVideoStreamId, m_pVideoInputType, pAttrVideo );
}
if ( m_pAudioInputType && m_pAudioOutputType )
{
   m_pSink->AddStream( m_pAudioOutputType, &m_dwAudioStreamId );
   // Attributes for encoding?
   CComPtr<IMFAttributes> pAttrAudio;

   // Not sure if these are needed
   //::MFCreateAttributes( &pAttrAudio, 2 );
   //pAttrAudio->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_AAC );
   //pAttrAudio->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, 16 );

   m_pSink->SetInputMediaType( m_dwAudioStreamId, m_pAudioInputType, pAttrAudio );
}
m_pSink->BeginWriting();

正在停止录制示例:

if ( m_dwVideoStreamId != (DWORD)-1 )
{
   m_sink->Flush( m_dwVideoStreamId );
}
if ( m_dwAudioStreamId != (DWORD)-1 )
{
   m_sink->Flush( m_dwAudioStreamId );
}

m_sink->Finalize();

Media Foundation 应用程序可能挂起的情况有很多:

  • 使用媒体基础对象时调用 MFShutDown/CoUninitialize。
  • 使用 GUI,并在多线程应用程序中错误地使用 windows 消息泵。
  • MTA/STA 个组件使用不当。
  • 事件函数的关键 section/wait 使用不当。
  • 使用 BeginXXX() 函数时忘记调用 EndXXX() 函数。
  • 回调函数使用不当。
  • 忘记在必要时调用AddRef,而释放另一个线程使用的对象。
  • Media Foundation 中的一个错误(Windows 七上有一些)。
  • 等等...

当我说最小的源代码时,我的意思是隔离执行编码过程的源代码,如果它太大则将其提供给 Github。如果能编译试试源码就更好了,死锁很难发现。