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. Возможно, это могут быть неверные данные или данные, не соответствующие установленным типам носителей.