diff options
Diffstat (limited to 'Src/aacdec-mft/mft-util.cpp')
-rw-r--r-- | Src/aacdec-mft/mft-util.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/Src/aacdec-mft/mft-util.cpp b/Src/aacdec-mft/mft-util.cpp new file mode 100644 index 00000000..7a71b665 --- /dev/null +++ b/Src/aacdec-mft/mft-util.cpp @@ -0,0 +1,191 @@ +#include "util.h" +#include <bfc/platform/types.h> +#include <mferror.h> +#include <mftransform.h> +#include <wmcodecdsp.h> +#include <Mfidl.h> +#include <Mfapi.h> + +struct AACUserData { + WORD wPayloadType; + WORD wAudioProfileLevelIndication; + WORD wStructType; + WORD wReserved1; + DWORD dwReserved2; + uint8_t buffer[16]; +}; + +HRESULT GetAACCodec(IMFTransform **pDecoder) +{ + HRESULT hr = S_OK; + UINT32 count = 0; + + IMFActivate **ppActivate = NULL; // Array of activation objects. + + MFT_REGISTER_TYPE_INFO info = { MFMediaType_Audio, MFAudioFormat_AAC }; + + UINT32 unFlags = MFT_ENUM_FLAG_SYNCMFT | + MFT_ENUM_FLAG_LOCALMFT | + MFT_ENUM_FLAG_SORTANDFILTER; + + hr = MFTEnumEx( + MFT_CATEGORY_AUDIO_DECODER, + unFlags, + &info, // Input type + NULL, // Output type + &ppActivate, + &count + ); + + + if (SUCCEEDED(hr) && count == 0) + { + hr = MF_E_TOPO_CODEC_NOT_FOUND; + } + + // Create the first decoder in the list. + + if (SUCCEEDED(hr)) + { + hr = ppActivate[0]->ActivateObject(IID_PPV_ARGS(pDecoder)); + } + + for (UINT32 i = 0; i < count; i++) + { + ppActivate[i]->Release(); + } + CoTaskMemFree(ppActivate); + return hr; +} + +bool AssociateFloat(IMFTransform *decoder) +{ + IMFMediaType *media_type; + DWORD index=0; + for (;;) + { + GUID subtype; + UINT32 bps; + HRESULT hr = decoder->GetOutputAvailableType(0, index++, &media_type); + if (hr != S_OK) + return false; + + if (media_type->GetGUID(MF_MT_SUBTYPE, &subtype) != S_OK + || media_type->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bps) != S_OK) + { + media_type->Release(); + return false; + } + + if (subtype == MFAudioFormat_Float && bps == 32) + { + hr = decoder->SetOutputType(0, media_type, 0); + media_type->Release(); + + return true; + } + media_type->Release(); + } +} + +static uint32_t SampleRateForASC(const void *asc, size_t aacConfigLength) +{ + const uint8_t *pAacConfig = (const uint8_t *)asc; + const uint32_t samplingRates[]={96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,0}; + int index; + if (aacConfigLength >= 5 && (pAacConfig[4] >> 7) == 1) + { + index = (pAacConfig[4] >> 3) & 0x7; + + } else if (aacConfigLength >= 2) { + index = ((pAacConfig[0] & 0x7) << 1) | (pAacConfig[1] >> 7); // bits 5-8 + } else { + index = 12; + } + return samplingRates[index]; +} + +HRESULT CreateAACDecoder(IMFTransform **pDecoder, const void *asc, size_t asc_bytes) +{ + HRESULT hr; + IMFMediaType *media_type; + + hr = GetAACCodec(pDecoder); + if (FAILED(hr)) { + return hr; + } + + hr = MFCreateMediaType(&media_type); + if (FAILED(hr)) { + return hr; + } + hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); + hr = media_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC); + // + hr = media_type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0); // The stream contains raw_data_block elements only. + uint8_t profile_level =0xFE;// MP4GetAudioProfileLevel(mp4_file); + hr = media_type->SetUINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, profile_level); + media_type->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, SampleRateForASC(asc, asc_bytes)); + + // this is such a pain in the ass, it's part of an HEAACWAVEINFO struct packed together with the ASC data + AACUserData aacinfo; + aacinfo.wPayloadType = 0; + aacinfo.wAudioProfileLevelIndication = profile_level; + aacinfo.wStructType = 0; + + if (asc && asc_bytes) { + if (asc_bytes > 16) { // don't overrun the buffer + return E_FAIL; + } + memcpy(aacinfo.buffer, asc, asc_bytes); + + hr = media_type->SetBlob(MF_MT_USER_DATA, (const UINT8 *)&aacinfo, 12+(UINT)asc_bytes); + } + + hr = (*pDecoder)->SetInputType(0, media_type, 0); + if (FAILED(hr)) { + return hr; + } + media_type->Release(); + media_type=0; + + AssociateFloat(*pDecoder); + + return S_OK; +} + +HRESULT CreateADTSDecoder(IMFTransform **pDecoder) +{ + HRESULT hr; + IMFMediaType *media_type; + + hr = GetAACCodec(pDecoder); + if (FAILED(hr)) { + return hr; + } + + hr = MFCreateMediaType(&media_type); + if (FAILED(hr)) { + return hr; + } + hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); + hr = media_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC); + hr = media_type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 1); // ADTS + //hr = media_type->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16); // 16 bits per sample + uint8_t profile_level =0xFE;// MP4GetAudioProfileLevel(mp4_file); + hr = media_type->SetUINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, profile_level); + + const BYTE user_data[] = {0x01, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + hr = media_type->SetBlob(MF_MT_USER_DATA, user_data, sizeof(user_data)); + + hr = (*pDecoder)->SetInputType(0, media_type, 0); + if (FAILED(hr)) { + return hr; + } + media_type->Release(); + media_type=0; + + AssociateFloat(*pDecoder); + + return S_OK; +} |