IMFTransform::ProcessOutput возвращает E_INVALIDARG

Эта проблема

Я пытаюсь позвонить ProcessOutput получить декодированные данные из моего декодера и получить следующую ошибку:

E_INVALIDARG Один или несколько аргументов неверны.

Что я пробовал

Как ProcessOutput есть много аргументов, которые я пытался точно определить, в чем может быть ошибка. Документация дляProcessOutput не упоминает E_INVALIDARG, Тем не менее, документация дляMFT_OUTPUT_DATA_BUFFER, тип данных для одного из аргументов, упоминает в разделе "Замечания", что:

Любые другие комбинации являются недействительными и вызывают ProcessOutput возвращать E_INVALIDARG

О чем это говорит, так это о том, как MFT_OUTPUT_DATA_BUFFER структура настроена. Так что неправильно настроен MFT_OUTPUT_DATA_BUFFER может вызвать эту ошибку. Однако я попытался настроить его правильно.

Вызывая GetOutputStreamInfo, я нахожу, что мне нужно выделить образец, отправленный ProcessOutput, что я и делаю. Я использую почти тот же метод, который работал для ProcessInput, поэтому я не знаю, что я делаю здесь неправильно.

Я также пытался убедиться, что другие аргументы, которые по логике также должны быть в состоянии вызвать E_INVALIDARG, Они выглядят хорошо для меня, и я не смог найти никаких других указаний на то, какой из моих аргументов ProcessOutput может быть недействительным.

Код

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

"Прелюдия"

...
hr = pDecoder->lpVtbl->SetOutputType(pDecoder, dwOutputStreamID, pMediaOut, dwFlags);
...
// Send input to decoder
hr = pDecoder->lpVtbl->ProcessInput(pDecoder, dwInputStreamID, pSample, dwFlags);
if (FAILED(hr)) { /* did not fail */ }

Поэтому перед интересным кодом, приведенным ниже, я успешно настроил вещи (надеюсь) и отправил их в ProcessInput, который не вышел из строя. У меня есть 1 входной поток и 1 выходной поток, вход AAC, выход PCM.

Код, непосредственно приводящий к ошибке

// Input has now been sent to the decoder
// To extract a sample from the decoder we need to create a strucure to hold the output
// First we ask the OutputStream for what type of output sample it will produce and who should allocate it
// Then we create both the sample in question (if we should allocate it that is) and the MFT_OUTPUT_DATA_BUFFER
// which holds the sample and some other information that the decoder will fill in.

#define SAMPLES_PER_BUFFER 1 // hardcoded here, should depend on GetStreamIDs results, which right now is 1

MFT_OUTPUT_DATA_BUFFER pOutputSamples[SAMPLES_PER_BUFFER];
DWORD *pdwStatus = NULL;

// There are different allocation models, find out which one is required here.
MFT_OUTPUT_STREAM_INFO streamInfo = { 0,0,0 };
MFT_OUTPUT_STREAM_INFO *pStreamInfo = &streamInfo;

hr = pDecoder->lpVtbl->GetOutputStreamInfo(pDecoder, dwOutputStreamID, pStreamInfo);
if (FAILED(hr)) { ... }

if (pStreamInfo->dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) { ... }
else if (pStreamInfo->dwFlags == MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) { ... }
else {  
    // default, the client must allocate the output samples for the stream
    IMFSample *pOutSample = NULL;
    DWORD minimumSizeOfBuffer = pStreamInfo->cbSize;
    IMFMediaBuffer *pBuffer = NULL;

    // CreateMediaSample is explained further down. 
    hr = CreateMediaSample(minimumSizeOfBuffer, sampleDuration, &pBuffer, &pOutSample);
        if (FAILED(hr)) {
            BGLOG_ERROR("error");
        }

    pOutputSamples[0].pSample = pOutSample;
}

// since GetStreamIDs return E_NOTIMPL then dwStreamID does not matter
// but its recomended that it is set to the array index, 0 in this case.
// dwOutputStreamID will be 0 when E_NOTIMPL is returned by GetStremIDs
pOutputSamples[0].dwStreamID = dwOutputStreamID; // = 0
pOutputSamples[0].dwStatus = 0;
pOutputSamples[0].pEvents = NULL; // have tried init this myself, but MFT_OUTPUT_DATA_BUFFER documentation says not to.

hr = pDecoder->lpVtbl->ProcessOutput(pDecoder, dwFlags, outputStreamCount, pOutputSamples, pdwStatus);
if (FAILED(hr)) {
    // here E_INVALIDARG is found.
}

CreateMediaSample, который используется в коде, получен из примера из официальной документации, но изменен для вызова SetSampleDuration и SetSampleTime. Я получаю ту же ошибку, не устанавливая эти два, хотя это должно быть что-то другое, вызывающее проблему.

Некоторые из фактических данных, которые были отправлены в ProcessOutput

На случай, если я пропустил что-то, что легко увидеть по фактическим данным:

hr = pDecoder->lpVtbl->ProcessOutput(
    pDecoder, // my decoder
    dwFlags, // 0
    outputStreamCount, // 1 (from GetStreamCount)
    pOutputSamples, // se comment below
    pdwStatus // NULL
);
// pOutputSamples[0] holds this struct:
// dwStreamID = 0, 
// pSample = SampleDefinedBelow 
// dwStatus = 0, 
// pEvents = NULL

// SampleDefinedBelow:
// time = 0
// duration = 0.9523..
// buffer = with max length set correctly 
// attributes[] = NULL

Вопрос

Так что у кого-нибудь есть идеи о том, что я делаю неправильно или как я могу отладить это дальше?

1 ответ

Решение

ProcessOutput нужен действительный указатель в качестве последнего аргумента, так что это не работает:

DWORD *pdwStatus = NULL;
pDecoder->lpVtbl->ProcessOutput(..., pdwStatus);

Это нормально:

DWORD dwStatus;
pDecoder->lpVtbl->ProcessOutput(..., &dwStatus);

Что касается дальнейшего E_FAIL - Ваши выводы выше, в целом, выглядят хорошо. Не то, чтобы я видел что-то очевидное, а также код ошибки не говорит о том, что проблема связана с потоком данных MFT. Возможно, это могут быть неверные данные или данные, не соответствующие установленным типам носителей.

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