I'm trying to set the input type on a instance of the CLSID_MSAACDecMFT
object, but it always fails with
The data specified for the media type is invalid, inconsistent, or not supported by this object.
Based on the Microsoft documentation I've set the mandatory values before attempting to set it as input:
ComPtr<IUnknown> pUnknown = nullptr;
HRESULT hResult = CoCreateInstance(CLSID_MSAACDecMFT, nullptr, CLSCTX_INPROC_SERVER, IID_IUnknown, &pUnknown);
if (S_OK != hResult) {
LogError("Failed to create AAC decoder");
return false;
}
hResult = pUnknown->QueryInterface(IID_PPV_ARGS(&mAudioDecoder));
if (hResult != S_OK) {
LogError("Failed to create AAC decoder");
return false;
}
ComPtr<IMFMediaType> pInputMediaType = nullptr;
hResult = MFCreateMediaType(&pInputMediaType);
if (S_OK != hResult) {
return false;
}
pInputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
pInputMediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC);
pInputMediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16);
pInputMediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000);
pInputMediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2);
Can anyone tell me why this fails?
Many thanks, Peter
Well this was a pain! Misread the documents and there is an additional field to set, the MF_MT_USER_DATA
field. After a lot of trial and error, I got it:
hResult = MFCreateMediaType(&pInputMediaType);
if (S_OK != hResult) {
return false;
}
pInputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
pInputMediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC);
std::shared_ptr<AudioMp4Track> audioTrack = mDemuxer->getAudioTrack();
pInputMediaType->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0);
pInputMediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, audioTrack->getSampleRate());
pInputMediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, audioTrack->getChannelCount());
// This is the desired output bits, why it goes into input, I do not know.
pInputMediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32);
// This 14 byte array consists of the HEAACWAVEINFO struct members after WaveFormatEx plus a 2 byte config header
// Config (from https://wiki.multimedia.cx/index.php/MPEG-4_Audio):
// Type (5 bits)
// Sample Rate Index (4 bits)
// Channel Map Index (4 bits)
// Reserved and 0 (3 bits)
// 2 bytes in total
// 00001 0011 0010 000 0x0990
uint8_t config[] = { 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x90 };
How to set the MF_MF_USER_DATA
wasn't very clear, you don't need to create the WAVEFORMATEX
object or anything like that, you only need to set a blob on the media type, representing the relevant fields after wave format struct.
What will also potentially be of use to people is how to generate the output type... The documents only say that there are three mandatory fields: num channels, bits and sample rate. This didn't work for me, but I iterated through the list of possible output types and, provided there is a float output type, took it and used it:
ComPtr<IMFMediaType> pOutputType = nullptr;
hResult = MFCreateMediaType(&pOutputType);
if (S_OK != hResult) {
return false;
}
GUID guidSubType;
for (int i = 0; i < 10; ++i) {
ComPtr<IMFMediaType> pTempOutputType = nullptr;
hResult = MFCreateMediaType(&pTempOutputType);
if (S_OK != hResult) {
return false;
}
hResult = mAudioDecoder->GetOutputAvailableType(0, i, &pTempOutputType);
if (hResult == MF_E_NO_MORE_TYPES) {
break;
}
hResult = pTempOutputType->GetGUID(MF_MT_SUBTYPE, &guidSubType);
if (S_OK != hResult) {
LogError("oh no");
continue;
}
if (guidSubType == MFAudioFormat_Float) {
pTempOutputType->CopyAllItems(pOutputType.Get());
break;
}
}
uint32_t floatOutputBits = 0;
pOutputType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &floatOutputBits);
if (floatOutputBits != 32) {
LogError("No float output type for decoder");
return false;
}
hResult = mAudioDecoder->SetOutputType(0, pOutputType.Get(), 0);
if (S_OK != hResult) {
LogError("Couldn't set output type of audio decoder.");
return false;
}