2016-09-26 16 views
2

Для декодирования H264 потока с основой Windows Media Transform, поток работы в настоящее время что-то вроде этого:Windows, MFT (Media Foundation Transform) декодер не возвращает правильное время выборки или длительности

IMFSample sample; 
sample->SetTime(time_in_ns); 
sample->SetDuration(duration_in_ns); 
sample->AddBuffer(buffer); 

// Feed IMFSample to decoder 
mDecoder->ProcessInput(0, sample, 0); 

// Get output from decoder. 
/* create outputsample that will receive content */ { ... } 
MFT_OUTPUT_DATA_BUFFER output = {0}; 
output.pSample = outputsample; 
DWORD status = 0; 
HRESULT hr = mDecoder->ProcessOutput(0, 1, &output, &status); 
DWORD status = 0; 
hr = mDecoder->ProcessOutput(0, 1, &output, &status); 
if (output.pEvents) { 
    // We must release this, as per the IMFTransform::ProcessOutput() 
    // MSDN documentation. 
    output.pEvents->Release(); 
    output.pEvents = nullptr; 
} 

if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { 
    // Type change, probably geometric aperture change. 
    // Reconfigure decoder output type, so that GetOutputMediaType() 
} else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { 
    // Not enough input to produce output. 
} else if (!output.pSample) { 
    return S_OK; 
} else } 
    // Process output 
} 

}

Когда мы подавали все данные в MFT декодер, мы должны осушить его:

mDecoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0); 

Теперь, одна вещь с декодером WMF H264, является то, что он обычно не выводится все, что было вызвано с более чем 30 сжатыми кадрами h264 независимо от размера скользящего окна h264. Латентность очень высока ...

Я столкнулся с проблемой, которая очень хлопотная. С видео, сделанным только из ключевых кадров, и который имеет только 15 кадров, каждый из которых имеет длину 2 с, первый кадр имеет время представления отличного от нуля (этот поток из живого контента, поэтому первый кадр, как правило, находится в времени эпоса) Таким образом, без дренирования декодера ничего не выйдет из декодера, так как он не получил достаточного количества кадров.

Однако, как только декодер разрядится, декодированный кадр выйдет. ОДНАКО, MFT-декодер установил все длительности только 33,6 мс, а время представления первого отснятого образца всегда 0. Исходная продолжительность и время представления потеряны.

Если вы предоставите более 30 кадров к h264 декодер, то и продолжительность и баллы действительны ...

Я еще не нашел способ, чтобы получить WMF декодер для вывода образцов с соответствующим значением. Похоже, что если вам нужно слить декодер, прежде чем он выведет какие-либо образцы сам по себе, то он полностью сломан ...

У кого-нибудь возникли такие проблемы? Как вы обошли его?

Спасибо заранее

редактирование: образец видео доступно на http://people.mozilla.org/~jyavenard/mediatest/fragmented/1301869.mp4 Воспроизведение видео с Firefox будет заставляет его играть очень быстро из-за проблем, описанных выше.

+1

Вы должны попробовать 'CODECAPI_AVLowLatencyMode' [[1] (https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd797815), [2] (https://msdn.microsoft.com)./библиотека/окно/настольный/hh447590)]. –

+0

низкая латентность доступна только из окна 8 и более поздних версий. Кроме того, несовместимо с чем-либо, содержащим B-Frames. Кроме того, при включении было много аварий с драйверами ... Низкая латентность помогла бы здесь, хотя будет иметь такую ​​же проблему, если бы у меня было <8 кадров. – jyavenard

+0

Я боюсь, что вы упомянули поведение по дизайну. Исходные кадры доступны асинхронно (особенно в режиме DXVA), низкая латентность в Windows 8+, чтобы немного улучшить ситуацию, изменили тайминги, когда H.264 встраивает данные, связанные с временем. Разумеется, для сбоев драйверов требуются обновления драйверов. Полагаю, что только декодер с программным обеспечением может иметь более предсказуемое поведение. –

ответ

1

Я не уверен, что ваш рабочий поток верен. Я думаю, что вы должны сделать что-то вроде этого:

do 
{ 
    ... 
    hr = mDecoder->ProcessInput(0, sample, 0); 
    if(FAILED(hr)) 
     break; 
    ... 
    hr = mDecoder->ProcessOutput(0, 1, &output, &status); 
    if(FAILED(hr) && hr != MF_E_TRANSFORM_NEED_MORE_INPUT) 
     break; 
} 
while(hr == MF_E_TRANSFORM_NEED_MORE_INPUT); 

if(SUCCEEDED(hr)) 
{ 
    // You have a valid decoded frame here 
} 

Идея заключается в том, чтобы продолжать называть ProcessInput/ProcessOuptut в то время как ProcessOutput возвращает MF_E_TRANSFORM_NEED_MORE_INPUT. MF_E_TRANSFORM_NEED_MORE_INPUT означает, что декодеру требуется больше ввода. Я думаю, что с этим циклом вам не нужно будет истощать декодер.

+0

То, что вы описываете, ничем не отличается от того, что у меня есть. Я представил только рабочий процесс только для одного кадра. Конечно, если у вас более одного кадра, вы зацикливаетесь ... Однако проблема в том, что если вы вызываете ProcessInput менее 30 раз, вы, как правило, ничего не выходите из ProcessOutput. Здесь требуется дренирование. – jyavenard

+0

"MF_E_TRANSFORM_NEED_MORE_INPUT означает, что декодеру требуется больше ввода" обязательно ... но что делать, если вам нечего больше дать декодеру, когда вы достигли конца потока? – jyavenard

+0

Как установить тип входа декодера? Вы устанавливаете полностью описанный тип IMFMediaType или только основной тип и подтип? Вы проверили, возвращает ли ProcessOutput MF_E_TRANSFORM_STREAM_CHANGE? Можете ли вы попытаться вызвать ProcessInput в цикле, чтобы узнать, вернет ли он MF_E_NOTACCEPTING? Теперь я вижу, что у вас недостаточно кадров для подачи на декодер, но для вывода образца может потребоваться полная GOP. У вас есть начальные коды, включенные в каждый кадр? Декодер пропускает байты до тех пор, пока не найдет допустимый набор параметров последовательности (SPS) и набор параметров изображения (PPS) в потоке байтов. – VuVirt