summaryrefslogtreecommitdiffstats
path: root/media/gmp-clearkey/0.1/WMFAACDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/gmp-clearkey/0.1/WMFAACDecoder.cpp')
-rw-r--r--media/gmp-clearkey/0.1/WMFAACDecoder.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/media/gmp-clearkey/0.1/WMFAACDecoder.cpp b/media/gmp-clearkey/0.1/WMFAACDecoder.cpp
new file mode 100644
index 000000000..495f840e8
--- /dev/null
+++ b/media/gmp-clearkey/0.1/WMFAACDecoder.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2013, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WMFAACDecoder.h"
+#include <algorithm>
+#include <stdint.h>
+#include <vector>
+
+using std::vector;
+
+namespace wmf {
+
+WMFAACDecoder::WMFAACDecoder()
+ : mDecoder(nullptr)
+ , mChannels(0)
+ , mRate(0)
+{
+ memset(&mInputStreamInfo, 0, sizeof(MFT_INPUT_STREAM_INFO));
+ memset(&mOutputStreamInfo, 0, sizeof(MFT_OUTPUT_STREAM_INFO));
+}
+
+WMFAACDecoder::~WMFAACDecoder()
+{
+ Reset();
+}
+
+HRESULT
+AACAudioSpecificConfigToUserData(BYTE* aAudioSpecConfig, UINT32 aConfigLength,
+ BYTE** aOutUserData, UINT32* aOutUserDataLength)
+{
+ // For MFAudioFormat_AAC, MF_MT_USER_DATA
+ // Contains the portion of the HEAACWAVEINFO structure that appears
+ // after the WAVEFORMATEX structure (that is, after the wfx member).
+ // This is followed by the AudioSpecificConfig() data, as defined
+ // by ISO/IEC 14496-3.
+ // ...
+ // The length of the AudioSpecificConfig() data is 2 bytes for AAC-LC
+ // or HE-AAC with implicit signaling of SBR/PS. It is more than 2 bytes
+ // for HE-AAC with explicit signaling of SBR/PS.
+ //
+ // The value of audioObjectType as defined in AudioSpecificConfig()
+ // must be 2, indicating AAC-LC. The value of extensionAudioObjectType
+ // must be 5 for SBR or 29 for PS.
+ //
+ // See:
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/dd742784%28v=vs.85%29.aspx
+ //
+ // HEAACWAVEINFO structure:
+ // typedef struct heaacwaveinfo_tag {
+ // WAVEFORMATEX wfx;
+ // WORD wPayloadType;
+ // WORD wAudioProfileLevelIndication;
+ // WORD wStructType;
+ // WORD wReserved1;
+ // DWORD dwReserved2;
+ // }
+ const UINT32 heeInfoLen = 4 * sizeof(WORD) + sizeof(DWORD);
+ BYTE heeInfo[heeInfoLen] = {0};
+ WORD* w = (WORD*)heeInfo;
+ w[0] = 0x0; // Payload type raw AAC
+ w[1] = 0; // Profile level unspecified
+
+ const UINT32 len = heeInfoLen + aConfigLength;
+ BYTE* data = new BYTE[len];
+ memcpy(data, heeInfo, heeInfoLen);
+ memcpy(data+heeInfoLen, aAudioSpecConfig, aConfigLength);
+ *aOutUserData = data;
+ *aOutUserDataLength = len;
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::Init(int32_t aChannelCount,
+ int32_t aSampleRate,
+ BYTE* aAACAudioSpecificConfig,
+ UINT32 aAudioConfigLength)
+{
+ HRESULT hr;
+
+ // AAC decoder is in msauddecmft on Win8, and msmpeg2adec in earlier versions.
+ hr = CreateMFT(CLSID_CMSAACDecMFT,
+ WMFDecoderDllNameFor(AAC),
+ mDecoder);
+ if (FAILED(hr)) {
+ hr = CreateMFT(CLSID_CMSAACDecMFT,
+ WMFDecoderDllNameFor(AAC),
+ mDecoder);
+ if (FAILED(hr)) {
+ LOG("Failed to create AAC decoder\n");
+ return E_FAIL;
+ }
+ }
+
+ BYTE* userData = nullptr;
+ UINT32 userDataLength;
+ hr = AACAudioSpecificConfigToUserData(aAACAudioSpecificConfig,
+ aAudioConfigLength,
+ &userData,
+ &userDataLength);
+ ENSURE(SUCCEEDED(hr), hr);
+ hr = SetDecoderInputType(aChannelCount, aSampleRate, userData, userDataLength);
+ delete userData;
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = SetDecoderOutputType();
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = mDecoder->GetInputStreamInfo(0, &mInputStreamInfo);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = mDecoder->GetOutputStreamInfo(0, &mOutputStreamInfo);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::SetDecoderInputType(int32_t aChannelCount,
+ int32_t aSampleRate,
+ BYTE* aUserData,
+ UINT32 aUserDataLength)
+{
+ HRESULT hr;
+
+ CComPtr<IMFMediaType> type;
+ hr = MFCreateMediaType(&type);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ mRate = aSampleRate;
+ hr = type->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, mRate);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ mChannels = aChannelCount;
+ hr = type->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, mChannels);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = type->SetBlob(MF_MT_USER_DATA, aUserData, aUserDataLength);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = mDecoder->SetInputType(0, type, 0);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::SetDecoderOutputType()
+{
+ HRESULT hr;
+
+ CComPtr<IMFMediaType> type;
+
+ UINT32 typeIndex = 0;
+ while (type = nullptr, SUCCEEDED(mDecoder->GetOutputAvailableType(0, typeIndex++, &type))) {
+ GUID subtype;
+ hr = type->GetGUID(MF_MT_SUBTYPE, &subtype);
+ if (FAILED(hr)) {
+ continue;
+ }
+ if (subtype == MFAudioFormat_PCM) {
+ hr = mDecoder->SetOutputType(0, type, 0);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &mChannels);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = type->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &mRate);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+HRESULT
+WMFAACDecoder::SendMFTMessage(MFT_MESSAGE_TYPE aMsg, UINT32 aData)
+{
+ ENSURE(mDecoder != nullptr, E_POINTER);
+ HRESULT hr = mDecoder->ProcessMessage(aMsg, aData);
+ ENSURE(SUCCEEDED(hr), hr);
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::CreateInputSample(const uint8_t* aData,
+ uint32_t aDataSize,
+ Microseconds aTimestamp,
+ IMFSample** aOutSample)
+{
+ HRESULT hr;
+ CComPtr<IMFSample> sample = nullptr;
+ hr = MFCreateSample(&sample);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ CComPtr<IMFMediaBuffer> buffer = nullptr;
+ int32_t bufferSize = std::max<uint32_t>(uint32_t(mInputStreamInfo.cbSize), aDataSize);
+ UINT32 alignment = (mInputStreamInfo.cbAlignment > 1) ? mInputStreamInfo.cbAlignment - 1 : 0;
+ hr = MFCreateAlignedMemoryBuffer(bufferSize, alignment, &buffer);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ DWORD maxLength = 0;
+ DWORD currentLength = 0;
+ BYTE* dst = nullptr;
+ hr = buffer->Lock(&dst, &maxLength, &currentLength);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ // Copy data into sample's buffer.
+ memcpy(dst, aData, aDataSize);
+
+ hr = buffer->Unlock();
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = buffer->SetCurrentLength(aDataSize);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = sample->AddBuffer(buffer);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = sample->SetSampleTime(UsecsToHNs(aTimestamp));
+ ENSURE(SUCCEEDED(hr), hr);
+
+ *aOutSample = sample.Detach();
+
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::CreateOutputSample(IMFSample** aOutSample)
+{
+ HRESULT hr;
+ CComPtr<IMFSample> sample = nullptr;
+ hr = MFCreateSample(&sample);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ CComPtr<IMFMediaBuffer> buffer = nullptr;
+ int32_t bufferSize = mOutputStreamInfo.cbSize;
+ UINT32 alignment = (mOutputStreamInfo.cbAlignment > 1) ? mOutputStreamInfo.cbAlignment - 1 : 0;
+ hr = MFCreateAlignedMemoryBuffer(bufferSize, alignment, &buffer);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ hr = sample->AddBuffer(buffer);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ *aOutSample = sample.Detach();
+
+ return S_OK;
+}
+
+
+HRESULT
+WMFAACDecoder::GetOutputSample(IMFSample** aOutSample)
+{
+ HRESULT hr;
+ // We allocate samples for MFT output.
+ MFT_OUTPUT_DATA_BUFFER output = {0};
+
+ CComPtr<IMFSample> sample = nullptr;
+ hr = CreateOutputSample(&sample);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ output.pSample = sample;
+
+ DWORD status = 0;
+ hr = mDecoder->ProcessOutput(0, 1, &output, &status);
+ CComPtr<IMFCollection> events = output.pEvents; // Ensure this is released.
+
+ if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
+ // Type change. Probably geometric apperature change.
+ hr = SetDecoderOutputType();
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return GetOutputSample(aOutSample);
+ } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT || !sample) {
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+ // Treat other errors as fatal.
+ ENSURE(SUCCEEDED(hr), hr);
+
+ assert(sample);
+
+ *aOutSample = sample.Detach();
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::Input(const uint8_t* aData,
+ uint32_t aDataSize,
+ Microseconds aTimestamp)
+{
+ CComPtr<IMFSample> input = nullptr;
+ HRESULT hr = CreateInputSample(aData, aDataSize, aTimestamp, &input);
+ ENSURE(SUCCEEDED(hr) && input!=nullptr, hr);
+
+ hr = mDecoder->ProcessInput(0, input, 0);
+ if (hr == MF_E_NOTACCEPTING) {
+ // MFT *already* has enough data to produce a sample. Retrieve it.
+ LOG("ProcessInput returned MF_E_NOTACCEPTING\n");
+ return MF_E_NOTACCEPTING;
+ }
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::Output(IMFSample** aOutput)
+{
+ CComPtr<IMFSample> outputSample = nullptr;
+ HRESULT hr = GetOutputSample(&outputSample);
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+ // Treat other errors as fatal.
+ ENSURE(SUCCEEDED(hr) && outputSample, hr);
+
+ *aOutput = outputSample.Detach();
+
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::Reset()
+{
+ HRESULT hr = SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return S_OK;
+}
+
+HRESULT
+WMFAACDecoder::Drain()
+{
+ HRESULT hr = SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
+ ENSURE(SUCCEEDED(hr), hr);
+
+ return S_OK;
+}
+
+}