aboutsummaryrefslogtreecommitdiff
path: root/Src/aacdec/MP4AACDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/aacdec/MP4AACDecoder.cpp')
-rw-r--r--Src/aacdec/MP4AACDecoder.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/Src/aacdec/MP4AACDecoder.cpp b/Src/aacdec/MP4AACDecoder.cpp
new file mode 100644
index 00000000..c8f00003
--- /dev/null
+++ b/Src/aacdec/MP4AACDecoder.cpp
@@ -0,0 +1,236 @@
+#include "MP4AACDecoder.h"
+#include "api.h"
+#include <math.h>
+#include <bfc/platform/minmax.h>
+#include "../nsutil/pcm.h"
+
+
+
+// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
+static const GUID playbackConfigGroupGUID =
+ { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
+
+MP4AACDecoder::MP4AACDecoder()
+{
+ preDelay = 0;
+ decoder = 0;
+ access_unit = 0;
+ composition_unit = 0;
+ isFloat = false;
+ gain=1.0f;
+ // get bps
+ bitsPerSample = AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16);
+ if (bitsPerSample >= 24) bitsPerSample = 24;
+ else bitsPerSample = 16;
+
+ // get max channels
+ if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true))
+ maxChannels = 6;
+ else if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false))
+ maxChannels = 1;
+ else
+ maxChannels = 2;
+}
+
+int MP4AACDecoder::Open()
+{
+ /* with FhG's API, we can't actually create a decoder until we have the ASC.
+ best we can do right now is create the access unit object */
+ access_unit = CAccessUnit_Create(0, 0);
+ if (access_unit)
+ return MP4_SUCCESS;
+ else
+ return MP4_FAILURE;
+}
+
+int MP4AACDecoder::OpenEx(size_t _bits, size_t _maxChannels, bool useFloat)
+{
+ isFloat = useFloat;
+ if (isFloat)
+ {
+ bitsPerSample = 32;
+ }
+ else
+ {
+ if (_bits)
+ bitsPerSample = _bits;
+ if (bitsPerSample >= 24) bitsPerSample = 24;
+ else bitsPerSample = 16;
+ }
+ if (_maxChannels)
+ maxChannels = _maxChannels;
+ return Open();
+}
+
+int MP4AACDecoder::GetOutputProperties(unsigned int *sampleRate, unsigned int *channels, unsigned int *_bitsPerSample)
+{
+ bool dummy;
+ return GetOutputPropertiesEx(sampleRate, channels, _bitsPerSample, &dummy);
+}
+
+int MP4AACDecoder::GetOutputPropertiesEx(unsigned int *sampleRate, unsigned int *channels, unsigned int *_bitsPerSample, bool *useFloat)
+{
+ /* TODO: verify that it's safe to call these, e.g. one frame has been decoded successfully, otherwise call MKV_NEED_MORE_INPUT */
+ CCompositionUnit_GetSamplingRate(composition_unit, sampleRate);
+ CCompositionUnit_GetChannels(composition_unit, channels);
+
+ *_bitsPerSample = bitsPerSample;
+ *useFloat = isFloat;
+ return MP4_SUCCESS;
+}
+
+void MP4AACDecoder::Flush()
+{
+ mp4AudioDecoder_Reset(decoder, MP4AUDIODECPARAM_DEFAULT, 0);
+}
+
+int MP4AACDecoder::GetCurrentBitrate(unsigned int *bitrate)
+{
+ int current_bitrate;
+ if (CCompositionUnit_GetProperty(composition_unit, CUBUFFER_CURRENTBITRATE, &current_bitrate) == MP4AUDIODEC_OK)
+ {
+ *bitrate = current_bitrate/1000;
+ return MP4_SUCCESS;
+ }
+ else
+ return MP4_GETCURRENTBITRATE_UNKNOWN;
+}
+
+int MP4AACDecoder::DecodeSample(void *inputBuffer, size_t inputBufferBytes, void *outputBuffer, size_t *outputBufferBytes)
+{
+ CAccessUnit_Reset(access_unit);
+ CAccessUnit_Assign(access_unit, (const unsigned char *)inputBuffer, inputBufferBytes);
+ CCompositionUnit_Reset(composition_unit);
+ MP4_RESULT result = mp4AudioDecoder_DecodeFrame(decoder, &access_unit, composition_unit);
+
+ if (result == MP4AUDIODEC_OK)
+ {
+ unsigned int channels;
+ unsigned int samples_per_channel;
+ if (CCompositionUnit_GetSamplesPerChannel(composition_unit, &samples_per_channel) != MP4AUDIODEC_OK
+ || CCompositionUnit_GetChannels(composition_unit, &channels) != MP4AUDIODEC_OK)
+ return MP4_FAILURE;
+ const float *audio_output = 0;
+
+ size_t num_samples = samples_per_channel * channels;
+ size_t output_size = num_samples * (bitsPerSample/8);
+ if (output_size > *outputBufferBytes)
+ return MP4_FAILURE;
+
+ *outputBufferBytes = output_size;
+ CCompositionUnit_GetPcmPtr(composition_unit, &audio_output);
+ if (!isFloat)
+ {
+ nsutil_pcm_FloatToInt_Interleaved_Gain(outputBuffer, audio_output, bitsPerSample, num_samples, gain/32768.0f);
+ }
+ else
+ {
+ for (size_t i = 0;i != num_samples;i++)
+ ((float *)outputBuffer)[i] = audio_output[i] * gain / 32768.0f;
+ }
+
+ return MP4_SUCCESS;
+ }
+ else
+ return MP4_FAILURE;
+}
+
+int MP4AACDecoder::OutputFrameSize(size_t *frameSize)
+{
+ if (!decoder)
+ return MP4_FAILURE;
+
+ unsigned int samples_per_channel;
+ unsigned int channels;
+ if (CCompositionUnit_GetSamplesPerChannel(composition_unit, &samples_per_channel) != MP4AUDIODEC_OK
+ || CCompositionUnit_GetChannels(composition_unit, &channels) != MP4AUDIODEC_OK)
+ return MP4_FAILURE;
+
+ *frameSize = samples_per_channel*channels;
+ return MP4_SUCCESS;
+}
+
+
+int MP4AACDecoder::AudioSpecificConfiguration(void *buffer, size_t buffer_size) // reads ASC block from mp4 file
+{
+ // TODO: error check
+ if (buffer && buffer_size)
+ {
+ CSAudioSpecificConfig asc;
+ memset(&asc, 0, sizeof(asc));
+ if (mp4AudioDecoder_ascParse((const unsigned char *)buffer, buffer_size, &asc) == MP4AUDIODEC_OK)
+ {
+ CSAudioSpecificConfig *asc_array = &asc;;
+ decoder = mp4AudioDecoder_Create(&asc_array, 1);
+ if (decoder)
+ {
+ mp4AudioDecoder_SetParam(decoder, TDL_MODE, SWITCH_OFF);
+ mp4AudioDecoder_SetParam(decoder, CONCEALMENT_ENERGYINTERPOLATION, SWITCH_OFF);
+ composition_unit = CCompositionUnit_Create(max(asc.m_channels, 8), asc.m_samplesPerFrame * 2, asc.m_samplingFrequency, 6144, CUBUFFER_PCMTYPE_FLOAT);
+ return MP4_SUCCESS;
+ }
+ }
+ }
+
+ return MP4_FAILURE;
+}
+
+void MP4AACDecoder::Close()
+{
+ mp4AudioDecoder_Destroy(&decoder);
+ CAccessUnit_Destroy(&access_unit);
+ CCompositionUnit_Destroy(&composition_unit);
+}
+
+int MP4AACDecoder::CanHandleCodec(const char *codecName)
+{
+ return !strcmp(codecName, "mp4a");
+}
+
+int MP4AACDecoder::CanHandleType(uint8_t type)
+{
+ switch (type)
+ {
+ case MP4_TYPE_MPEG4_AUDIO:
+ return 1;
+ case MP4_TYPE_MPEG2_AAC_LC_AUDIO:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int MP4AACDecoder::CanHandleMPEG4Type(uint8_t type)
+{
+ switch (type)
+ {
+ case MP4_MPEG4_TYPE_AAC_LC_AUDIO:
+ case MP4_MPEG4_TYPE_AAC_HE_AUDIO:
+ case MP4_MPEG4_TYPE_PARAMETRIC_STEREO:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS MP4AACDecoder
+START_DISPATCH;
+CB(MPEG4_AUDIO_OPEN, Open)
+CB(MPEG4_AUDIO_OPEN_EX, OpenEx)
+CB(MPEG4_AUDIO_ASC, AudioSpecificConfiguration)
+CB(MPEG4_AUDIO_BITRATE, GetCurrentBitrate)
+CB(MPEG4_AUDIO_FRAMESIZE, OutputFrameSize)
+CB(MPEG4_AUDIO_OUTPUTINFO, GetOutputProperties)
+CB(MPEG4_AUDIO_OUTPUTINFO_EX, GetOutputPropertiesEx)
+CB(MPEG4_AUDIO_DECODE, DecodeSample)
+VCB(MPEG4_AUDIO_FLUSH, Flush)
+VCB(MPEG4_AUDIO_CLOSE, Close)
+CB(MPEG4_AUDIO_HANDLES_CODEC, CanHandleCodec)
+CB(MPEG4_AUDIO_HANDLES_TYPE, CanHandleType)
+CB(MPEG4_AUDIO_HANDLES_MPEG4_TYPE, CanHandleMPEG4Type)
+CB(MPEG4_AUDIO_SET_GAIN, SetGain)
+END_DISPATCH;