Запись видео зависает на IMFSinkWriter-> Завершить

Я реализовал пользовательский IMFMediaSink для использования с приемником записи. Работает хорошо, получает образцы видео h264. У меня нет никакого контейнера, я потребляю сырые образцы видео h264. Я не реализовал пользовательский модуль записи, я использую API MFCreateSinkWriterFromMediaSink, чтобы обернуть мой собственный приемник мультимедиа в модуль записи, предоставленный платформой.

Я не могу осуществить постепенное отключение, IMFSinkWriter::Finalize() никогда не вернется. Когда я реализовал IMFSinkWriterCallback, IMFSinkWriter::Finalize() возвращается сразу, но мой IMFSinkWriterCallback::OnFinalize никогда не звонил.

Проблема воспроизводится в 100% тестах с программным кодером nvenc и MS.

Атрибуты писателя:

MF_LOW_LATENCY = TRUE
MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS = TRUE (1)
MF_READWRITE_DISABLE_CONVERTERS = FALSE (2)
MF_SINK_WRITER_DISABLE_THROTTLING = TRUE
MF_SINK_WRITER_D3D_MANAGER
MF_SINK_WRITER_ASYNC_CALLBACK

(1) Пробовал оба, тот же результат

(2) Нужны конвертеры, потому что nvenc поддерживает только YUV и у меня есть RGB текстуры на входе.

Тип выходного носителя (это исправлено, я использую встроенный обработчик, созданный MFCreateSimpleTypeHandler API).

MF_MT_MAJOR_TYPE = MFMediaType_Video
MF_MT_SUBTYPE = MFVideoFormat_H264
MF_MT_INTERLACE_MODE = MFVideoInterlace_Progressive
MF_MT_AVG_BITRATE = 40*1000*1000
MF_MT_FRAME_SIZE = { 3840, 2160 }
MF_MT_FRAME_RATE = { 60, 1 }
MF_MT_PIXEL_ASPECT_RATIO = { 1, 1 }

Тип носителя ввода:

MF_MT_MAJOR_TYPE = MFMediaType_Video
MF_MT_SUBTYPE = MFVideoFormat_RGB32
MF_MT_INTERLACE_MODE = MFVideoInterlace_Progressive
MF_MT_FRAME_SIZE = { 3840, 2160 }
MF_MT_FRAME_RATE = { 60, 1 }
MF_MT_PIXEL_ASPECT_RATIO = { 1, 1 }

Когда IMFSinkWriterCallback не используется, вот стек вызовов во время зависания:

ntdll.dll!_NtWaitForSingleObject@12 ()
KernelBase.dll!WaitForSingleObjectEx()
mfreadwrite.dll!CMFSinkWriter::InternalFinalize(void)
mfreadwrite.dll!CMFSinkWriter::Finalize(void)

MFTrace не имеет ничего общего, чтобы завершить даже с -k All:

13700,3C60 19:01:25.79566 CMFTransformDetours::ProcessOutput @02EA6E3C failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
13700,2A98 19:01:25.80250 CMFTransformDetours::ProcessOutput @1A6CEF38 Stream ID 0, Sample @1C244F30, Time 1216ms, Duration 16ms, Buffers 1, Size 12441600B, MFSampleExtension_CleanPoint=1;MFSampleExtension_Interlaced=0
13700,2098 19:01:25.80254 CMFTransformDetours::ProcessInput @02EA6E3C Stream ID 0, Sample @1C244F30, Time 1216ms, Duration 16ms, Buffers 1, Size 12441600B, MFSampleExtension_CleanPoint=1;MFSampleExtension_Interlaced=0
13700,2A98 19:01:25.80256 CMFTransformDetours::ProcessOutput @1A6CEF38 failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
13700,2A98 19:01:25.80266 CMFTransformDetours::ProcessMessage @1A6CEF38 Message type=0x00000001 MFT_MESSAGE_COMMAND_DRAIN, param=00000000
13700,2A98 19:01:25.80267 CMFTransformDetours::ProcessOutput @1A6CEF38 failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
13700,2098 19:01:25.81669 CMFTransformDetours::ProcessOutput @02EA6E3C Stream ID 0, Sample @1FB68CF8, Time 1216ms, Duration 16ms, Buffers 1, Size 680B, {2B5D5457-5547-4F07-B8C8-B4A3A9A1DAAC}=1;{73A954D4-09E2-4861-BEFC-94BD97C08E6E}=12166667 (0,12166667);{9154733F-E1BD-41BF-81D3-FCD918F71332}=65535;{973704E6-CD14-483C-8F20-C9FC0928BAD5}=1;MFSampleExtension_CleanPoint=0;{B2EFE478-F979-4C66-B95E-EE2B82C82F36}=16 (0,16)
13700,82C 19:01:25.81674 CMFTransformDetours::ProcessOutput @02EA6E3C failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
13700,82C 19:01:25.81674 CMFTransformDetours::ProcessMessage @02EA6E3C Message type=0x00000001 MFT_MESSAGE_COMMAND_DRAIN, param=00000000
13700,82C 19:01:25.81674 CMFTransformDetours::ProcessOutput @02EA6E3C failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
13700,1F54 19:01:27.24237 CKernel32ExportDetours::OutputDebugStringA @ D3D11 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN] 
13700,1F54 19:01:27.24255 CKernel32ExportDetours::OutputDebugStringA @ D3D11 WARNING: Live Producer at 0x0311D91C, Refcount: 13. [ STATE_CREATION WARNING #0: UNKNOWN] 

Предупреждения о живых ресурсах D3D ожидаются, когда я завершил процесс после зависания.

Есть идеи, что происходит? Я думаю, что автор, вероятно, ожидает появления этих магических объектов SPS/PPS, но этого не происходит. Есть ли способ проинструктировать кодер h264 для вывода SPS/PPS где-нибудь?

1 ответ

Вы реализовали пользовательский IMFMediaSink, поэтому я полагаю, что вы также реализовали IMFStreamSink.

Делая это обычным способом с Mediafoundation, вы получаете круговую ссылку COM между IMFMediaSink и IMFStreamSink. Вот почему существует метод Shutdown из интерфейса IMFMediaSink.

Если программа, использующая ваш пользовательский MediaSink, не вызывает Shutdown в нужном месте, произойдут утечки памяти.

Из-за вашей проблемы IMFSinkWriterCallback у нас недостаточно информации, чтобы найти причину проблемы.

Также неясно про "кастомные IMFMediaSink" и "IMFSinkWriter". Вы также используете IMFSinkWriter...

EDIT1

Всего две вещи:

MFCreateSinkWriterFromMediaSink

Вызовите CoInitialize(Ex) и MFStartup перед вызовом этой функции.

Когда вы закончите использовать приемник мультимедиа, вызовите метод IMFMediaSink::Shutdown приемника мультимедиа. (Устройство записи приемника не закрывает приемник носителя.) Отпустите устройство записи приемника, прежде чем вызывать Shutdown на приемнике носителя.

вы правильно выпускаете интерфейсы?

IMFSinkWriter:: Доработка

Внутренне этот метод вызывает IMFStreamSink::PlaceMarker для размещения маркеров конца сегмента для каждого потока в приемнике мультимедиа.

Обрабатываете ли вы это сообщение (MFSTREAMSINK_MARKER_ENDOFSEGMENT)?

Мы не знаем, как вы обрабатываете CriticalSection/Event/CircularReference, поэтому трудно найти проблему.

EDIT2

Есть ли способ проинструктировать кодер h264 для вывода SPS/PPS где-нибудь?

Обычно для формата видео h264 вам необходимо получить атрибуты MF_MT_MPEG_SEQUENCE_HEADER (тип BLOB), когда SetCurrentMediaType вызывается на IMFStreamSink (предполагается, что вы реализуете IMFMediaTypeHandler).

EDIT3

Не могли бы вы предоставить реальный (вот как я думаю, приложение должно быть):

топология и поток данных

Я не помню, создает ли ваш пользовательский приемник файл mp4. Если это так, в IMFSinkWriter::Finalize вы должны сгенерировать атом ftpy/moov.

EDIT4

Также вы можете прочитать это: Запись видео зависает на IMFSinkWriter->Finalize();

Без исходного кода это единственный ответ, который я могу дать.

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