视频录制挂在IMFSinkWriter->Finalize();上
Video Recording Hangs on IMFSinkWriter->Finalize();
使用媒体基础将视频录制最终录制到.mp4时遇到问题,IMFSinkWriter->Finalize();
的调用永远挂起。它并不总是发生,几乎可以在任何机器上发生(在Windows服务器上看到,7,8,10(。 事先在音频和视频流上调用Flush()
,并且在Flush
和Finalize
之间不会添加新样本。关于什么可能导致Finalize
永远悬而未决的任何想法?
我尝试过的事情:
- 记录所有
HRESULT
以检查任何问题(在继续下一行代码之前已经检查了它们(
一切都恢复了
S_OK
,没有看到任何问题
- 在流中添加了
IMFSinkWriterCallback
,以便在以下情况下获取回调流处理标记(每 10 个样本添加标记(和完成Finalize()
自从添加这个以来一直无法重现,但这将提供有关我让它工作时发生的事情的最佳信息。
- 在线搜索代码示例,了解其他人如何设置接收器编写器以及如何使用
Finalize()
没有找到很多示例,看起来我的代码与找到的代码相似
- 查看了每个系统可用和使用的编码器,包括编码器dll的版本
在可能重现该问题的计算机上,编码器在 AMD H.264 硬件 MFT 编码器和 H264 编码器 MFT 之间有所不同。版本似乎并不重要,有些机器是最新的视频驱动程序。
以下是一些没有任何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();
在很多情况下,媒体基础应用程序可能会挂起:
- 使用媒体基础对象时调用 MFShutDown/CoUninitialize。 使用
- GUI,并在多线程应用程序中错误地使用 Windows 消息泵。
- MTA/STA 组件使用不当。
- 关键部分/等待事件功能使用不当。
- 忘记在使用 BeginXXX(( 函数时调用 EndXXX(( 函数。
- 回调函数使用不当。
- 忘记在必要时调用 AddRef,并释放另一个线程使用的对象。
- Media Foundation 中的一个错误(Windows Seven 上有一些(。
- 等等...
当我说最小的源代码时,我的意思是,隔离执行编码过程的源代码,如果它太大,则将其提供给Github。如果我们可以编译并尝试源代码会更好,因为死锁很难找到。