我在使用 Media Foundation 将视频录制完成为 .mp4 时遇到问题,其中调用IMFSinkWriter->Finalize();
永远挂起。它并不总是发生,并且几乎可以在任何计算机上发生(在 Windows 服务器、7、8、10 上可见)。Flush()
事先在音频和视频流上调用,并且之间不添加新样本Flush
and Finalize
。关于可能导致什么的任何想法Finalize
永远挂起来?
我尝试过的事情:
- 记录全部
HRESULT
检查是否有任何问题(在继续下一行代码之前已经检查过它们)
一切都回来了S_OK
,没有看到任何问题
- 添加了
IMFSinkWriterCallback
在流上获取回调
流处理标记(每 10 个样本添加标记)并完成Finalize()
自从添加此功能以来一直无法重现,但这将提供有关当我让它工作时发生的情况的最佳信息。
- 网上搜索代码示例,看看其他人是如何设置的
Sink Writer 以及如何使用
Finalize()
is used
没有找到很多示例,看起来我的代码与找到的代码类似
- 查看每个系统可用和使用的编码器,包括编码器 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();