diff options
author | Dave Burke <daveburke@google.com> | 2012-04-02 13:54:42 -0700 |
---|---|---|
committer | Dave Burke <daveburke@google.com> | 2012-04-02 16:29:02 -0700 |
commit | b7ddcc9460f488f0b032aeb27b52a423318a97ea (patch) | |
tree | 144761751558f6ea77d79b86befebda742f50e3d /media/libstagefright/codecs/aacdec | |
parent | ecdd39c5af016e2fa57cbfd837aa670b706dabd3 (diff) | |
download | frameworks_av-b7ddcc9460f488f0b032aeb27b52a423318a97ea.zip frameworks_av-b7ddcc9460f488f0b032aeb27b52a423318a97ea.tar.gz frameworks_av-b7ddcc9460f488f0b032aeb27b52a423318a97ea.tar.bz2 |
Add support for a new AAC decoder library.
Change-Id: I867bf95f7c20503e55b38d0087ac027647834f37
Diffstat (limited to 'media/libstagefright/codecs/aacdec')
-rw-r--r-- | media/libstagefright/codecs/aacdec/Android.mk | 377 | ||||
-rw-r--r-- | media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 492 | ||||
-rw-r--r-- | media/libstagefright/codecs/aacdec/SoftAAC2.h | 73 |
3 files changed, 770 insertions, 172 deletions
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk index b4445a7..5b3d216 100644 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ b/media/libstagefright/codecs/aacdec/Android.mk @@ -1,180 +1,213 @@ LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - analysis_sub_band.cpp \ - apply_ms_synt.cpp \ - apply_tns.cpp \ - buf_getbits.cpp \ - byte_align.cpp \ - calc_auto_corr.cpp \ - calc_gsfb_table.cpp \ - calc_sbr_anafilterbank.cpp \ - calc_sbr_envelope.cpp \ - calc_sbr_synfilterbank.cpp \ - check_crc.cpp \ - dct16.cpp \ - dct64.cpp \ - decode_huff_cw_binary.cpp \ - decode_noise_floorlevels.cpp \ - deinterleave.cpp \ - digit_reversal_tables.cpp \ - dst16.cpp \ - dst32.cpp \ - dst8.cpp \ - esc_iquant_scaling.cpp \ - extractframeinfo.cpp \ - fft_rx4_long.cpp \ - fft_rx4_short.cpp \ - fft_rx4_tables_fxp.cpp \ - find_adts_syncword.cpp \ - fwd_long_complex_rot.cpp \ - fwd_short_complex_rot.cpp \ - gen_rand_vector.cpp \ - get_adif_header.cpp \ - get_adts_header.cpp \ - get_audio_specific_config.cpp \ - get_dse.cpp \ - get_ele_list.cpp \ - get_ga_specific_config.cpp \ - get_ics_info.cpp \ - get_prog_config.cpp \ - get_pulse_data.cpp \ - get_sbr_bitstream.cpp \ - get_sbr_startfreq.cpp \ - get_sbr_stopfreq.cpp \ - get_tns.cpp \ - getfill.cpp \ - getgroup.cpp \ - getics.cpp \ - getmask.cpp \ - hcbtables_binary.cpp \ - huffcb.cpp \ - huffdecode.cpp \ - hufffac.cpp \ - huffspec_fxp.cpp \ - idct16.cpp \ - idct32.cpp \ - idct8.cpp \ - imdct_fxp.cpp \ - infoinit.cpp \ - init_sbr_dec.cpp \ - intensity_right.cpp \ - inv_long_complex_rot.cpp \ - inv_short_complex_rot.cpp \ - iquant_table.cpp \ - long_term_prediction.cpp \ - long_term_synthesis.cpp \ - lt_decode.cpp \ - mdct_fxp.cpp \ - mdct_tables_fxp.cpp \ - mdst.cpp \ - mix_radix_fft.cpp \ - ms_synt.cpp \ - pns_corr.cpp \ - pns_intensity_right.cpp \ - pns_left.cpp \ - ps_all_pass_filter_coeff.cpp \ - ps_all_pass_fract_delay_filter.cpp \ - ps_allocate_decoder.cpp \ - ps_applied.cpp \ - ps_bstr_decoding.cpp \ - ps_channel_filtering.cpp \ - ps_decode_bs_utils.cpp \ - ps_decorrelate.cpp \ - ps_fft_rx8.cpp \ - ps_hybrid_analysis.cpp \ - ps_hybrid_filter_bank_allocation.cpp \ - ps_hybrid_synthesis.cpp \ - ps_init_stereo_mixing.cpp \ - ps_pwr_transient_detection.cpp \ - ps_read_data.cpp \ - ps_stereo_processing.cpp \ - pulse_nc.cpp \ - pv_div.cpp \ - pv_log2.cpp \ - pv_normalize.cpp \ - pv_pow2.cpp \ - pv_sine.cpp \ - pv_sqrt.cpp \ - pvmp4audiodecoderconfig.cpp \ - pvmp4audiodecoderframe.cpp \ - pvmp4audiodecodergetmemrequirements.cpp \ - pvmp4audiodecoderinitlibrary.cpp \ - pvmp4audiodecoderresetbuffer.cpp \ - q_normalize.cpp \ - qmf_filterbank_coeff.cpp \ - sbr_aliasing_reduction.cpp \ - sbr_applied.cpp \ - sbr_code_book_envlevel.cpp \ - sbr_crc_check.cpp \ - sbr_create_limiter_bands.cpp \ - sbr_dec.cpp \ - sbr_decode_envelope.cpp \ - sbr_decode_huff_cw.cpp \ - sbr_downsample_lo_res.cpp \ - sbr_envelope_calc_tbl.cpp \ - sbr_envelope_unmapping.cpp \ - sbr_extract_extended_data.cpp \ - sbr_find_start_andstop_band.cpp \ - sbr_generate_high_freq.cpp \ - sbr_get_additional_data.cpp \ - sbr_get_cpe.cpp \ - sbr_get_dir_control_data.cpp \ - sbr_get_envelope.cpp \ - sbr_get_header_data.cpp \ - sbr_get_noise_floor_data.cpp \ - sbr_get_sce.cpp \ - sbr_inv_filt_levelemphasis.cpp \ - sbr_open.cpp \ - sbr_read_data.cpp \ - sbr_requantize_envelope_data.cpp \ - sbr_reset_dec.cpp \ - sbr_update_freq_scale.cpp \ - set_mc_info.cpp \ - sfb.cpp \ - shellsort.cpp \ - synthesis_sub_band.cpp \ - tns_ar_filter.cpp \ - tns_decode_coef.cpp \ - tns_inv_filter.cpp \ - trans4m_freq_2_time_fxp.cpp \ - trans4m_time_2_freq_fxp.cpp \ - unpack_idx.cpp \ - window_tables_fxp.cpp \ - pvmp4setaudioconfig.cpp \ - -LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= -DOSCL_UNUSED_ARG= - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - -LOCAL_ARM_MODE := arm - -LOCAL_MODULE := libstagefright_aacdec - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ + +AAC_LIBRARY = pv + +ifeq ($(AAC_LIBRARY), fraunhofer) + include $(CLEAR_VARS) + + LOCAL_SRC_FILES := \ + SoftAAC2.cpp + + LOCAL_C_INCLUDES := \ + frameworks/av/media/libstagefright/include \ + frameworks/native/include/media/openmax \ + external/aac/libAACdec/include \ + external/aac/libCDK/include \ + external/aac/libMpegTPDec/include \ + external/aac/libSBRdec/include \ + external/aac/libSYS/include + + LOCAL_CFLAGS := + + LOCAL_STATIC_LIBRARIES := \ + libAACdec libMpegTPDec libSBRdec libCDK libSYS + + LOCAL_SHARED_LIBRARIES := \ + libstagefright_omx libstagefright_foundation libutils + + LOCAL_MODULE := libstagefright_soft_aacdec + LOCAL_MODULE_TAGS := optional + + include $(BUILD_SHARED_LIBRARY) + +else # pv + + LOCAL_SRC_FILES := \ + analysis_sub_band.cpp \ + apply_ms_synt.cpp \ + apply_tns.cpp \ + buf_getbits.cpp \ + byte_align.cpp \ + calc_auto_corr.cpp \ + calc_gsfb_table.cpp \ + calc_sbr_anafilterbank.cpp \ + calc_sbr_envelope.cpp \ + calc_sbr_synfilterbank.cpp \ + check_crc.cpp \ + dct16.cpp \ + dct64.cpp \ + decode_huff_cw_binary.cpp \ + decode_noise_floorlevels.cpp \ + deinterleave.cpp \ + digit_reversal_tables.cpp \ + dst16.cpp \ + dst32.cpp \ + dst8.cpp \ + esc_iquant_scaling.cpp \ + extractframeinfo.cpp \ + fft_rx4_long.cpp \ + fft_rx4_short.cpp \ + fft_rx4_tables_fxp.cpp \ + find_adts_syncword.cpp \ + fwd_long_complex_rot.cpp \ + fwd_short_complex_rot.cpp \ + gen_rand_vector.cpp \ + get_adif_header.cpp \ + get_adts_header.cpp \ + get_audio_specific_config.cpp \ + get_dse.cpp \ + get_ele_list.cpp \ + get_ga_specific_config.cpp \ + get_ics_info.cpp \ + get_prog_config.cpp \ + get_pulse_data.cpp \ + get_sbr_bitstream.cpp \ + get_sbr_startfreq.cpp \ + get_sbr_stopfreq.cpp \ + get_tns.cpp \ + getfill.cpp \ + getgroup.cpp \ + getics.cpp \ + getmask.cpp \ + hcbtables_binary.cpp \ + huffcb.cpp \ + huffdecode.cpp \ + hufffac.cpp \ + huffspec_fxp.cpp \ + idct16.cpp \ + idct32.cpp \ + idct8.cpp \ + imdct_fxp.cpp \ + infoinit.cpp \ + init_sbr_dec.cpp \ + intensity_right.cpp \ + inv_long_complex_rot.cpp \ + inv_short_complex_rot.cpp \ + iquant_table.cpp \ + long_term_prediction.cpp \ + long_term_synthesis.cpp \ + lt_decode.cpp \ + mdct_fxp.cpp \ + mdct_tables_fxp.cpp \ + mdst.cpp \ + mix_radix_fft.cpp \ + ms_synt.cpp \ + pns_corr.cpp \ + pns_intensity_right.cpp \ + pns_left.cpp \ + ps_all_pass_filter_coeff.cpp \ + ps_all_pass_fract_delay_filter.cpp \ + ps_allocate_decoder.cpp \ + ps_applied.cpp \ + ps_bstr_decoding.cpp \ + ps_channel_filtering.cpp \ + ps_decode_bs_utils.cpp \ + ps_decorrelate.cpp \ + ps_fft_rx8.cpp \ + ps_hybrid_analysis.cpp \ + ps_hybrid_filter_bank_allocation.cpp \ + ps_hybrid_synthesis.cpp \ + ps_init_stereo_mixing.cpp \ + ps_pwr_transient_detection.cpp \ + ps_read_data.cpp \ + ps_stereo_processing.cpp \ + pulse_nc.cpp \ + pv_div.cpp \ + pv_log2.cpp \ + pv_normalize.cpp \ + pv_pow2.cpp \ + pv_sine.cpp \ + pv_sqrt.cpp \ + pvmp4audiodecoderconfig.cpp \ + pvmp4audiodecoderframe.cpp \ + pvmp4audiodecodergetmemrequirements.cpp \ + pvmp4audiodecoderinitlibrary.cpp \ + pvmp4audiodecoderresetbuffer.cpp \ + q_normalize.cpp \ + qmf_filterbank_coeff.cpp \ + sbr_aliasing_reduction.cpp \ + sbr_applied.cpp \ + sbr_code_book_envlevel.cpp \ + sbr_crc_check.cpp \ + sbr_create_limiter_bands.cpp \ + sbr_dec.cpp \ + sbr_decode_envelope.cpp \ + sbr_decode_huff_cw.cpp \ + sbr_downsample_lo_res.cpp \ + sbr_envelope_calc_tbl.cpp \ + sbr_envelope_unmapping.cpp \ + sbr_extract_extended_data.cpp \ + sbr_find_start_andstop_band.cpp \ + sbr_generate_high_freq.cpp \ + sbr_get_additional_data.cpp \ + sbr_get_cpe.cpp \ + sbr_get_dir_control_data.cpp \ + sbr_get_envelope.cpp \ + sbr_get_header_data.cpp \ + sbr_get_noise_floor_data.cpp \ + sbr_get_sce.cpp \ + sbr_inv_filt_levelemphasis.cpp \ + sbr_open.cpp \ + sbr_read_data.cpp \ + sbr_requantize_envelope_data.cpp \ + sbr_reset_dec.cpp \ + sbr_update_freq_scale.cpp \ + set_mc_info.cpp \ + sfb.cpp \ + shellsort.cpp \ + synthesis_sub_band.cpp \ + tns_ar_filter.cpp \ + tns_decode_coef.cpp \ + tns_inv_filter.cpp \ + trans4m_freq_2_time_fxp.cpp \ + trans4m_time_2_freq_fxp.cpp \ + unpack_idx.cpp \ + window_tables_fxp.cpp \ + pvmp4setaudioconfig.cpp \ + + LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= -DOSCL_UNUSED_ARG= + + LOCAL_C_INCLUDES := \ + frameworks/av/media/libstagefright/include \ + + LOCAL_ARM_MODE := arm + + LOCAL_MODULE := libstagefright_aacdec + + include $(BUILD_STATIC_LIBRARY) + + ################################################################################ + + include $(CLEAR_VARS) + + LOCAL_SRC_FILES := \ SoftAAC.cpp -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax + LOCAL_C_INCLUDES := \ + frameworks/av/media/libstagefright/include \ + frameworks/native/include/media/openmax + + LOCAL_CFLAGS := -DOSCL_IMPORT_REF= -LOCAL_CFLAGS := -DOSCL_IMPORT_REF= + LOCAL_STATIC_LIBRARIES := \ + libstagefright_aacdec -LOCAL_STATIC_LIBRARIES := \ - libstagefright_aacdec + LOCAL_SHARED_LIBRARIES := \ + libstagefright_omx libstagefright_foundation libutils -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils + LOCAL_MODULE := libstagefright_soft_aacdec + LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := libstagefright_soft_aacdec -LOCAL_MODULE_TAGS := optional + include $(BUILD_SHARED_LIBRARY) -include $(BUILD_SHARED_LIBRARY) +endif # $(AAC_LIBRARY) diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp new file mode 100644 index 0000000..4589d37 --- /dev/null +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "SoftAAC2" +#include <utils/Log.h> + +#include "SoftAAC2.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/hexdump.h> + +#define FILEREAD_MAX_LAYERS 2 + +namespace android { + +static Mutex gAACLibraryLock; +static int gAACLibraryCount = 0; + +void initializeAACLibrary() { + Mutex::Autolock autoLock(gAACLibraryLock); + if (gAACLibraryCount++ == 0) { + CDKprolog(); + } +} + +void cleanupAACLibrary() { + Mutex::Autolock autoLock(gAACLibraryLock); + if (--gAACLibraryCount == 0) { + CDKepilog(); + } +} + +template<class T> +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +SoftAAC2::SoftAAC2( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mAACDecoder(NULL), + mStreamInfo(NULL), + mIsADTS(false), + mInputBufferCount(0), + mSignalledError(false), + mAnchorTimeUs(0), + mNumSamplesOutput(0), + mOutputPortSettingsChange(NONE) { + initializeAACLibrary(); + initPorts(); + CHECK_EQ(initDecoder(), (status_t)OK); +} + +SoftAAC2::~SoftAAC2() { + aacDecoder_Close(mAACDecoder); + cleanupAACLibrary(); +} + +void SoftAAC2::initPorts() { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 8192; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.audio.cMIMEType = const_cast<char *>("audio/aac"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 8192; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + addPort(def); +} + +status_t SoftAAC2::initDecoder() { + status_t status = UNKNOWN_ERROR; + mAACDecoder = aacDecoder_Open(TT_MP4_RAW, /* num layers */ 1); + if (mAACDecoder != NULL) { + mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder); + if (mStreamInfo != NULL) { + status = OK; + } + } + return status; +} + +OMX_ERRORTYPE SoftAAC2::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexParamAudioAac: + { + OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = + (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; + + if (aacParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + aacParams->nBitRate = 0; + aacParams->nAudioBandWidth = 0; + aacParams->nAACtools = 0; + aacParams->nAACERtools = 0; + aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; + + aacParams->eAACStreamFormat = + mIsADTS + ? OMX_AUDIO_AACStreamFormatMP4ADTS + : OMX_AUDIO_AACStreamFormatMP4FF; + + aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; + + if (!isConfigured()) { + aacParams->nChannels = 1; + aacParams->nSampleRate = 44100; + aacParams->nFrameLength = 0; + } else { + aacParams->nChannels = mStreamInfo->channelConfig; + aacParams->nSampleRate = mStreamInfo->aacSampleRate; + aacParams->nFrameLength = mStreamInfo->aacSamplesPerFrame; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + pcmParams->eNumData = OMX_NumericalDataSigned; + pcmParams->eEndian = OMX_EndianBig; + pcmParams->bInterleaved = OMX_TRUE; + pcmParams->nBitPerSample = 16; + pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; + pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; + pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; + + if (!isConfigured()) { + pcmParams->nChannels = 1; + pcmParams->nSamplingRate = 44100; + } else { + pcmParams->nChannels = mStreamInfo->channelConfig; + pcmParams->nSamplingRate = mStreamInfo->sampleRate; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftAAC2::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + switch (index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (strncmp((const char *)roleParams->cRole, + "audio_decoder.aac", + OMX_MAX_STRINGNAME_SIZE - 1)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAac: + { + const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = + (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params; + + if (aacParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { + mIsADTS = false; + } else if (aacParams->eAACStreamFormat + == OMX_AUDIO_AACStreamFormatMP4ADTS) { + mIsADTS = true; + } else { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +bool SoftAAC2::isConfigured() const { + return mInputBufferCount > 0; +} + +void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { + if (mSignalledError || mOutputPortSettingsChange != NONE) { + return; + } + + UCHAR* inBuffer[FILEREAD_MAX_LAYERS]; + UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0}; + UINT bytesValid[FILEREAD_MAX_LAYERS] = {0}; + AAC_DECODER_ERROR decoderErr; + + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &outQueue = getPortQueue(1); + + if (portIndex == 0 && mInputBufferCount == 0) { + ++mInputBufferCount; + BufferInfo *info = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *header = info->mHeader; + + inBuffer[0] = header->pBuffer + header->nOffset; + inBufferLength[0] = header->nFilledLen; + + AAC_DECODER_ERROR decoderErr = + aacDecoder_ConfigRaw(mAACDecoder, + inBuffer, + inBufferLength); + + if (decoderErr != AAC_DEC_OK) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + + inQueue.erase(inQueue.begin()); + info->mOwnedByUs = false; + notifyEmptyBufferDone(header); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + return; + } + + while (!inQueue.empty() && !outQueue.empty()) { + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + + outHeader->nFilledLen = 0; + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + return; + } + + if (inHeader->nOffset == 0) { + mAnchorTimeUs = inHeader->nTimeStamp; + mNumSamplesOutput = 0; + } + + if (mIsADTS) { + // skip 30 bits, aac_frame_length follows. + // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? + + const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; + + CHECK_GE(inHeader->nFilledLen, 7); + + bool protectionAbsent = (adtsHeader[1] & 1); + + unsigned aac_frame_length = + ((adtsHeader[3] & 3) << 11) + | (adtsHeader[4] << 3) + | (adtsHeader[5] >> 5); + + CHECK_GE(inHeader->nFilledLen, aac_frame_length); + + size_t headerSize = (protectionAbsent ? 7 : 9); + + inBuffer[0] = (UCHAR *)adtsHeader + headerSize; + inBufferLength[0] = aac_frame_length - headerSize; + + inHeader->nOffset += headerSize; + inHeader->nFilledLen -= headerSize; + } else { + inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; + inBufferLength[0] = inHeader->nFilledLen; + } + + + // Fill and decode + INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset); + bytesValid[0] = inBufferLength[0]; + + int prevSampleRate = mStreamInfo->sampleRate; + decoderErr = aacDecoder_Fill(mAACDecoder, + inBuffer, + inBufferLength, + bytesValid); + decoderErr = aacDecoder_DecodeFrame(mAACDecoder, + outBuffer, + outHeader->nAllocLen, + /* flags */ 0); + + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (decoderErr == AAC_DEC_OK && mInputBufferCount <= 2) { + if (mStreamInfo->sampleRate != prevSampleRate) { + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + return; + } + } + + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; + + if (decoderErr == AAC_DEC_OK) { + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; + } else { + ALOGW("AAC decoder returned error %d, substituting silence", + decoderErr); + + memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); + + // Discard input buffer. + inHeader->nFilledLen = 0; + + // fall through + } + + if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) { + // We'll only output data if we successfully decoded it or + // we've previously decoded valid data, in the latter case + // (decode failed) we'll output a silent frame. + outHeader->nFilledLen = numOutBytes; + outHeader->nFlags = 0; + + outHeader->nTimeStamp = + mAnchorTimeUs + + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate; + + mNumSamplesOutput += mStreamInfo->frameSize; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + } + + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + + if (decoderErr == AAC_DEC_OK) { + ++mInputBufferCount; + } + } +} + +void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { + if (portIndex == 0) { + + // Make sure that the next buffer output does not still + // depend on fragments from the last one decoded. + aacDecoder_DecodeFrame(mAACDecoder, + NULL, + 0, + AACDEC_FLUSH); + } +} + +void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { + if (portIndex != 1) { + return; + } + + switch (mOutputPortSettingsChange) { + case NONE: + break; + + case AWAITING_DISABLED: + { + CHECK(!enabled); + mOutputPortSettingsChange = AWAITING_ENABLED; + break; + } + + default: + { + CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); + CHECK(enabled); + mOutputPortSettingsChange = NONE; + break; + } + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + return new android::SoftAAC2(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h new file mode 100644 index 0000000..828b34e --- /dev/null +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef SOFT_AAC_2_H_ +#define SOFT_AAC_2_H_ + +#include "SimpleSoftOMXComponent.h" + +#include "aacdecoder_lib.h" + +namespace android { + +struct SoftAAC2 : public SimpleSoftOMXComponent { + SoftAAC2(const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftAAC2(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params); + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params); + + virtual void onQueueFilled(OMX_U32 portIndex); + virtual void onPortFlushCompleted(OMX_U32 portIndex); + virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); + +private: + enum { + kNumBuffers = 4 + }; + + HANDLE_AACDECODER mAACDecoder; + CStreamInfo *mStreamInfo; + bool mIsADTS; + size_t mInputBufferCount; + bool mSignalledError; + int64_t mAnchorTimeUs; + int64_t mNumSamplesOutput; + + enum { + NONE, + AWAITING_DISABLED, + AWAITING_ENABLED + } mOutputPortSettingsChange; + + void initPorts(); + status_t initDecoder(); + bool isConfigured() const; + + DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2); +}; + +} // namespace android + +#endif // SOFT_AAC_2_H_ |