aboutsummaryrefslogtreecommitdiff
path: root/Src/aacdec-mft/MFTDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/aacdec-mft/MFTDecoder.cpp')
-rw-r--r--Src/aacdec-mft/MFTDecoder.cpp209
1 files changed, 209 insertions, 0 deletions
diff --git a/Src/aacdec-mft/MFTDecoder.cpp b/Src/aacdec-mft/MFTDecoder.cpp
new file mode 100644
index 00000000..c0b32ec9
--- /dev/null
+++ b/Src/aacdec-mft/MFTDecoder.cpp
@@ -0,0 +1,209 @@
+#include "MFTDecoder.h"
+#include "util.h"
+#include "../nsutil/pcm.h"
+#include <Mfapi.h>
+#include <Mferror.h>
+
+static // Release the events that an MFT might allocate in IMFTransform::ProcessOutput().
+void ReleaseEventCollection(MFT_OUTPUT_DATA_BUFFER* pBuffers)
+{
+
+ if (pBuffers->pEvents)
+ {
+ pBuffers->pEvents->Release();
+ pBuffers->pEvents = NULL;
+ }
+
+}
+
+MFTDecoder::MFTDecoder()
+{
+ decoder=0;
+ output_buffer=0;
+ output_sample=0;
+}
+
+MFTDecoder::~MFTDecoder()
+{
+ if (decoder) {
+ decoder->Release();
+ }
+ decoder = 0;
+
+ if (output_buffer) {
+ output_buffer->Release();
+ }
+ output_buffer = 0;
+
+ if (output_sample) {
+ output_sample->Release();
+ }
+ output_sample = 0;
+}
+
+HRESULT MFTDecoder::Open(const void *asc, size_t asc_bytes)
+{
+ HRESULT hr = CreateAACDecoder(&decoder, asc, asc_bytes);
+ if (SUCCEEDED(hr)) {
+ decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
+ }
+ return hr;
+}
+
+HRESULT MFTDecoder::Open()
+{
+ HRESULT hr = CreateADTSDecoder(&decoder);
+ if (SUCCEEDED(hr)) {
+ decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
+ decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
+ }
+ return hr;
+}
+
+void MFTDecoder::Flush()
+{
+ if (decoder) {
+ decoder->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+ }
+}
+
+HRESULT MFTDecoder::GetOutputProperties(uint32_t *sampleRate, uint32_t *channels)
+{
+ HRESULT hr;
+ IMFMediaType *media_type;
+ UINT32 local_sample_rate, local_channels;
+
+ if (!decoder) {
+ return E_FAIL;
+ }
+
+ hr = decoder->GetOutputCurrentType(0, &media_type);
+
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (FAILED(hr=media_type->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &local_sample_rate))
+ || FAILED(hr=media_type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &local_channels))) {
+ media_type->Release();
+ return hr;
+ }
+
+ *sampleRate = local_sample_rate;
+ *channels = local_channels;
+
+ return hr;
+}
+
+HRESULT MFTDecoder::Feed(const void *inputBuffer, size_t inputBufferBytes)
+{
+ HRESULT hr;
+ if (inputBuffer && inputBufferBytes) {
+ IMFMediaBuffer *media_buffer=0;
+ IMFSample *media_sample=0;
+ MFCreateMemoryBuffer((DWORD)inputBufferBytes, &media_buffer);
+ MFCreateSample(&media_sample);
+ media_sample->AddBuffer(media_buffer);
+
+ BYTE *buffer;
+ DWORD max_length, current_length;
+ media_buffer->Lock(&buffer, &max_length, &current_length);
+ memcpy(buffer, inputBuffer, inputBufferBytes);
+
+ media_buffer->Unlock();
+ media_buffer->SetCurrentLength((DWORD)inputBufferBytes);
+
+ hr = decoder->ProcessInput(0, media_sample, 0);
+ media_sample->Release();
+ media_buffer->Release();
+ media_sample=0;
+ media_buffer=0;
+ } else {
+ decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
+ decoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
+ }
+ return S_OK;
+}
+
+HRESULT MFTDecoder::Decode(void *outputBuffer, size_t *outputBufferBytes, unsigned int bitsPerSample, bool isFloat, double gain)
+{
+ HRESULT hr;
+
+ if (!output_sample) {
+ MFT_OUTPUT_STREAM_INFO output_stream_info;
+ hr = decoder->GetOutputStreamInfo(0, &output_stream_info);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ MFCreateMemoryBuffer(output_stream_info.cbSize, &output_buffer);
+ MFCreateSample(&output_sample);
+ output_sample->AddBuffer(output_buffer);
+ }
+
+ output_buffer->SetCurrentLength(0);
+ MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0, output_sample, 0, 0};
+ DWORD status=0;
+ hr = decoder->ProcessOutput(0, 1, &output_data_buffer, &status);
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
+ *outputBufferBytes = 0;
+ return S_OK;
+ } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
+ AssociateFloat(decoder);
+ *outputBufferBytes = 0;
+ return hr;
+ }
+ IMFMediaBuffer *decimation_buffer;
+ hr = output_data_buffer.pSample->ConvertToContiguousBuffer(&decimation_buffer);
+ float *pcm;
+ DWORD max_length, current_length;
+ decimation_buffer->Lock((BYTE **)&pcm, &max_length, &current_length);
+ size_t num_samples = current_length / 4;
+ *outputBufferBytes = num_samples*bitsPerSample/8;
+
+ if (!isFloat)
+ {
+ nsutil_pcm_FloatToInt_Interleaved_Gain(outputBuffer, pcm, bitsPerSample, num_samples, (float)gain);
+ }
+ else
+ {
+ for (size_t i = 0;i != num_samples;i++)
+ ((float *)outputBuffer)[i] = pcm[i] * (float)gain;
+ }
+
+ decimation_buffer->Unlock();
+ decimation_buffer->Release();
+
+ ReleaseEventCollection(&output_data_buffer);
+
+ return S_OK;
+}
+
+HRESULT MFTDecoder::OutputBlockSizeSamples(size_t *frameSize)
+{
+ HRESULT hr;
+ MFT_OUTPUT_STREAM_INFO output_stream_info;
+
+ if (!decoder) {
+ return E_FAIL;
+ }
+
+ hr = decoder->GetOutputStreamInfo(0, &output_stream_info);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ *frameSize = output_stream_info.cbSize;
+ return hr;
+}
+
+bool MFTDecoder::AcceptingInput()
+{
+ DWORD flags;
+ if (decoder && SUCCEEDED(decoder->GetInputStatus(0, &flags))) {
+ if (flags & MFT_INPUT_STATUS_ACCEPT_DATA) {
+ return true;
+ }
+ }
+ return false;
+} \ No newline at end of file