diff options
Diffstat (limited to 'Src/aacdec-mft/MFTDecoder.cpp')
-rw-r--r-- | Src/aacdec-mft/MFTDecoder.cpp | 209 |
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, ¤t_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, ¤t_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 |