/* * Copyright (C) 2014 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. */ #include "DrcPresModeWrap.h" #include <assert.h> #define LOG_TAG "C2SoftAacDrcWrapper" //#define LOG_NDEBUG 0 #include <utils/Log.h> //#define DRC_PRES_MODE_WRAP_DEBUG #define GPM_ENCODER_TARGET_LEVEL 64 #define MAX_TARGET_LEVEL 40 CDrcPresModeWrapper::CDrcPresModeWrapper() { mDataUpdate = true; /* Data from streamInfo. */ /* Initialized to the same values as in the aac decoder */ mStreamPRL = -1; mStreamDRCPresMode = -1; mStreamNrAACChan = 0; mStreamNrOutChan = 0; /* Desired values (set by user). */ /* Initialized to the same values as in the aac decoder */ mDesTarget = -1; mDesAttFactor = 0; mDesBoostFactor = 0; mDesHeavy = 0; mEncoderTarget = -1; /* Values from last time. */ /* Initialized to the same values as the desired values */ mLastTarget = -1; mLastAttFactor = 0; mLastBoostFactor = 0; mLastHeavy = 0; } CDrcPresModeWrapper::~CDrcPresModeWrapper() { } void CDrcPresModeWrapper::setDecoderHandle(const HANDLE_AACDECODER handle) { mHandleDecoder = handle; } void CDrcPresModeWrapper::submitStreamData(CStreamInfo* pStreamInfo) { assert(pStreamInfo); if (mStreamPRL != pStreamInfo->drcProgRefLev) { mStreamPRL = pStreamInfo->drcProgRefLev; mDataUpdate = true; #ifdef DRC_PRES_MODE_WRAP_DEBUG ALOGV("DRC presentation mode wrapper: drcProgRefLev is %d\n", mStreamPRL); #endif } if (mStreamDRCPresMode != pStreamInfo->drcPresMode) { mStreamDRCPresMode = pStreamInfo->drcPresMode; mDataUpdate = true; #ifdef DRC_PRES_MODE_WRAP_DEBUG ALOGV("DRC presentation mode wrapper: drcPresMode is %d\n", mStreamDRCPresMode); #endif } if (mStreamNrAACChan != pStreamInfo->aacNumChannels) { mStreamNrAACChan = pStreamInfo->aacNumChannels; mDataUpdate = true; #ifdef DRC_PRES_MODE_WRAP_DEBUG ALOGV("DRC presentation mode wrapper: aacNumChannels is %d\n", mStreamNrAACChan); #endif } if (mStreamNrOutChan != pStreamInfo->numChannels) { mStreamNrOutChan = pStreamInfo->numChannels; mDataUpdate = true; #ifdef DRC_PRES_MODE_WRAP_DEBUG ALOGV("DRC presentation mode wrapper: numChannels is %d\n", mStreamNrOutChan); #endif } if (mStreamNrOutChan<mStreamNrAACChan) { mIsDownmix = true; } else { mIsDownmix = false; } if (mIsDownmix && (mStreamNrOutChan == 1)) { mIsMonoDownmix = true; } else { mIsMonoDownmix = false; } if (mIsDownmix && mStreamNrOutChan == 2){ mIsStereoDownmix = true; } else { mIsStereoDownmix = false; } } void CDrcPresModeWrapper::setParam(const DRC_PRES_MODE_WRAP_PARAM param, const int value) { switch (param) { case DRC_PRES_MODE_WRAP_DESIRED_TARGET: mDesTarget = value; break; case DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR: mDesAttFactor = value; break; case DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR: mDesBoostFactor = value; break; case DRC_PRES_MODE_WRAP_DESIRED_HEAVY: mDesHeavy = value; break; case DRC_PRES_MODE_WRAP_ENCODER_TARGET: mEncoderTarget = value; break; default: break; } mDataUpdate = true; } void CDrcPresModeWrapper::update() { // Get Data from Decoder int progRefLevel = mStreamPRL; int drcPresMode = mStreamDRCPresMode; // by default, do as desired int newTarget = mDesTarget; int newAttFactor = mDesAttFactor; int newBoostFactor = mDesBoostFactor; int newHeavy = mDesHeavy; if (mDataUpdate) { // sanity check if (mDesTarget < MAX_TARGET_LEVEL){ mDesTarget = MAX_TARGET_LEVEL; // limit target level to -10 dB or below newTarget = MAX_TARGET_LEVEL; } if (mEncoderTarget != -1) { if (mDesTarget<124) { // if target level > -31 dB if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) { // no stereo or mono downmixing, calculated scaling of light DRC /* use as little compression as possible */ newAttFactor = 0; newBoostFactor = 0; if (mDesTarget<progRefLevel) { // if target level > PRL if (mEncoderTarget < mDesTarget) { // if mEncoderTarget > target level // mEncoderTarget > target level > PRL int calcFactor; float calcFactor_norm; // 0.0f < calcFactor_norm < 1.0f calcFactor_norm = (float)(mDesTarget - progRefLevel) / (float)(mEncoderTarget - progRefLevel); calcFactor = (int)(calcFactor_norm*127.0f); // 0 <= calcFactor < 127 // calcFactor is the lower limit newAttFactor = (calcFactor>newAttFactor) ? calcFactor : newAttFactor; // new AttFactor will be always = calcFactor, as it is set to 0 before. newBoostFactor = newAttFactor; } else { /* target level > mEncoderTarget > PRL */ // newTDLimiterEnable = 1; // the time domain limiter must always be active in this case. // It is assumed that the framework activates it by default newAttFactor = 127; newBoostFactor = 127; } } else { // target level <= PRL // no restrictions required // newAttFactor = newAttFactor; } } else { // downmixing // if target level > -23 dB or mono downmix if ( (mDesTarget<92) || mIsMonoDownmix ) { newHeavy = 1; } else { // we perform a downmix, so, we need at least full light DRC newAttFactor = 127; } } } else { // target level <= -31 dB // playback -31 dB: light DRC only needed if we perform downmixing if (mIsDownmix) { // we do downmixing newAttFactor = 127; } } } else { // handle other used encoder target levels // Sanity check: DRC presentation mode is only specified for max. 5.1 channels if (mStreamNrAACChan > 6) { drcPresMode = 0; } switch (drcPresMode) { case 0: default: // presentation mode not indicated { if (mDesTarget<124) { // if target level > -31 dB // no stereo or mono downmixing if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) { if (mDesTarget<progRefLevel) { // if target level > PRL // newTDLimiterEnable = 1; // the time domain limiter must always be active in this case. // It is assumed that the framework activates it by default newAttFactor = 127; // at least, use light compression } else { // target level <= PRL // no restrictions required // newAttFactor = newAttFactor; } } else { // downmixing // newTDLimiterEnable = 1; // the time domain limiter must always be active in this case. // It is assumed that the framework activates it by default // if target level > -23 dB or mono downmix if ( (mDesTarget < 92) || mIsMonoDownmix ) { newHeavy = 1; } else{ // we perform a downmix, so, we need at least full light DRC newAttFactor = 127; } } } else { // target level <= -31 dB if (mIsDownmix) { // we do downmixing. // newTDLimiterEnable = 1; // the time domain limiter must always be active in this case. // It is assumed that the framework activates it by default newAttFactor = 127; } } } break; // Presentation mode 1 and 2 according to ETSI TS 101 154: // Digital Video Broadcasting (DVB); Specification for the use of Video and Audio Coding // in Broadcasting Applications based on the MPEG-2 Transport Stream, // section C.5.4., "Decoding", and Table C.33 // ISO DRC -> newHeavy = 0 (Use light compression, MPEG-style) // Compression_value -> newHeavy = 1 (Use heavy compression, DVB-style) // scaling restricted -> newAttFactor = 127 case 1: // presentation mode 1, Light:-31/Heavy:-23 { if (mDesTarget < 124) { // if target level > -31 dB // playback up to -23 dB newHeavy = 1; } else { // target level <= -31 dB // playback -31 dB if (mIsDownmix) { // we do downmixing. newAttFactor = 127; } } } break; case 2: // presentation mode 2, Light:-23/Heavy:-23 { if (mDesTarget < 124) { // if target level > -31 dB // playback up to -23 dB if (mIsMonoDownmix) { // if mono downmix newHeavy = 1; } else { newHeavy = 0; newAttFactor = 127; } } else { // target level <= -31 dB // playback -31 dB newHeavy = 0; if (mIsDownmix) { // we do downmixing. newAttFactor = 127; } } } break; } // switch() } // if (mEncoderTarget == GPM_ENCODER_TARGET_LEVEL) // sanity again if (newHeavy == 1) { newBoostFactor=127; // not really needed as the same would be done by the decoder anyway newAttFactor = 127; } // update the decoder if (newTarget != mLastTarget) { aacDecoder_SetParam(mHandleDecoder, AAC_DRC_REFERENCE_LEVEL, newTarget); mLastTarget = newTarget; #ifdef DRC_PRES_MODE_WRAP_DEBUG if (newTarget != mDesTarget) ALOGV("DRC presentation mode wrapper: forced target level to %d (from %d)\n", newTarget, mDesTarget); else ALOGV("DRC presentation mode wrapper: set target level to %d\n", newTarget); #endif } if (newAttFactor != mLastAttFactor) { aacDecoder_SetParam(mHandleDecoder, AAC_DRC_ATTENUATION_FACTOR, newAttFactor); mLastAttFactor = newAttFactor; #ifdef DRC_PRES_MODE_WRAP_DEBUG if (newAttFactor != mDesAttFactor) ALOGV("DRC presentation mode wrapper: forced attenuation factor to %d (from %d)\n", newAttFactor, mDesAttFactor); else ALOGV("DRC presentation mode wrapper: set attenuation factor to %d\n", newAttFactor); #endif } if (newBoostFactor != mLastBoostFactor) { aacDecoder_SetParam(mHandleDecoder, AAC_DRC_BOOST_FACTOR, newBoostFactor); mLastBoostFactor = newBoostFactor; #ifdef DRC_PRES_MODE_WRAP_DEBUG if (newBoostFactor != mDesBoostFactor) ALOGV("DRC presentation mode wrapper: forced boost factor to %d (from %d)\n", newBoostFactor, mDesBoostFactor); else ALOGV("DRC presentation mode wrapper: set boost factor to %d\n", newBoostFactor); #endif } if (newHeavy != mLastHeavy) { aacDecoder_SetParam(mHandleDecoder, AAC_DRC_HEAVY_COMPRESSION, newHeavy); mLastHeavy = newHeavy; #ifdef DRC_PRES_MODE_WRAP_DEBUG if (newHeavy != mDesHeavy) ALOGV("DRC presentation mode wrapper: forced heavy compression to %d (from %d)\n", newHeavy, mDesHeavy); else ALOGV("DRC presentation mode wrapper: set heavy compression to %d\n", newHeavy); #endif } #ifdef DRC_PRES_MODE_WRAP_DEBUG ALOGV("DRC config: tgt_lev: %3d, cut: %3d, boost: %3d, heavy: %d\n", newTarget, newAttFactor, newBoostFactor, newHeavy); #endif mDataUpdate = false; } // if (mDataUpdate) }