Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Video Recording Hangs on IMFSinkWriter->Finalize();

I have an issue when finalizing a video recording into an .mp4 using Media Foundation where the call to IMFSinkWriter->Finalize(); hangs forever. It doesn't always happen, and can happen on almost any machine (seen on Windows server, 7, 8, 10). Flush() is called on the audio and video streams before hand and no new samples are added between Flush and Finalize. Any ideas on what could cause Finalize to hang forever?

Things I've tried:

  • Logging all HRESULTs to check for any issues (was already checking them before proceeding to the next line of code)

Everything comes back as S_OK, not seeing any issues

  • Added the IMFSinkWriterCallback on the stream to get callbacks when the stream process markers (adding markers every 10 samples) and finishes Finalize()

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.

  • Searched code samples online to see how others are setting up the Sink Writer and how Finalize() is used

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

  • Looked at encoders available and used by each system including version of the encoder dll

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.

Here are some code samples without any HRESULT checking (that doubled the amount of code so I took it out)

Building the sink sample:

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();

Stopping the recording sample:

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

m_sink->Finalize();
like image 301
Anthony Avatar asked Nov 17 '15 21:11

Anthony


1 Answers

There is a lot of situation where a Media Foundation application can hang :

  • Calling MFShutDown/CoUninitialize when using Media Foundation objects.
  • Using a GUI, and doing bad use of windows message pump in multithreaded application.
  • Bad use of MTA/STA components.
  • Bad use of critical section/wait for event function.
  • Forget to call EndXXX() function when BeginXXX() function are used.
  • Bad use of Callback function.
  • Forget to call AddRef when necessary, and releasing the object used by another thread.
  • A bug in Media Foundation (there are some on Windows Seven).
  • and so on...

When i say a minimal source code, i mean, isolate the source code that do the encoding process, and provide it to Github if it's too large. It's better if we can compile and try the source code, because deadlock are difficult to find.

like image 165
mofo77 Avatar answered Nov 07 '22 22:11

mofo77