Запись видео зависает на IMFSinkWriter->Finalize();

У меня есть проблема при завершении записи видео в.mp4 с использованием Media Foundation, где вызов IMFSinkWriter->Finalize(); висит навсегда. Это не всегда происходит, и может случиться практически на любой машине (замечено на сервере Windows, 7, 8, 10). Flush() вызывается в аудио- и видеопотоках перед использованием, и между Flush а также Finalize, Любые идеи о том, что может вызвать Finalize навсегда повесить?

Вещи, которые я пробовал:

  • Регистрация всех HRESULTs, чтобы проверить наличие проблем (уже проверял их, прежде чем перейти к следующей строке кода)

Все возвращается как S_OK, не видя никаких проблем

  • Добавил IMFSinkWriterCallback в потоке, чтобы получить обратные вызовы, когда поток обрабатывает маркеры (добавляя маркеры каждые 10 выборок) и заканчивает Finalize()

Не смог воспроизвести с момента добавления этого, но это дало бы лучшую информацию о том, что происходит, когда я получу это работает.

  • Поиск примеров кода в Интернете, чтобы увидеть, как другие настраивают Sink Writer и как 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();

1 ответ

Решение

Существует много ситуаций, когда приложение Media Foundation может зависнуть:

  • Вызов MFShutDown/CoUninitialize при использовании объектов Media Foundation.
  • Использование графического интерфейса и плохое использование Windows сообщений в многопоточном приложении.
  • Неправильное использование компонентов MTA/STA.
  • Неправильное использование критической секции / ожидание функции события.
  • Забудьте вызывать функцию EndXXX() при использовании функции BeginXXX().
  • Неправильное использование функции обратного вызова.
  • Забудьте при необходимости вызвать AddRef и освободить объект, используемый другим потоком.
  • Ошибка в Media Foundation (есть некоторые в Windows Seven).
  • и так далее...

Когда я говорю минимальный исходный код, я имею в виду, изолировать исходный код, который выполняет процесс кодирования, и предоставить его Github, если он слишком большой. Лучше, если мы сможем скомпилировать и попробовать исходный код, потому что трудно найти тупик.

Другие вопросы по тегам