SoftG711.cpp revision 0490fe25b580546f54d4d5bdb184fa8df091dfc5
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "SoftG711" 19#include <utils/Log.h> 20 21#include "SoftG711.h" 22 23#include <media/stagefright/foundation/ADebug.h> 24#include <media/stagefright/MediaDefs.h> 25 26namespace android { 27 28template<class T> 29static void InitOMXParams(T *params) { 30 params->nSize = sizeof(T); 31 params->nVersion.s.nVersionMajor = 1; 32 params->nVersion.s.nVersionMinor = 0; 33 params->nVersion.s.nRevision = 0; 34 params->nVersion.s.nStep = 0; 35} 36 37SoftG711::SoftG711( 38 const char *name, 39 const OMX_CALLBACKTYPE *callbacks, 40 OMX_PTR appData, 41 OMX_COMPONENTTYPE **component) 42 : SimpleSoftOMXComponent(name, callbacks, appData, component), 43 mIsMLaw(true), 44 mNumChannels(1), 45 mSignalledError(false) { 46 if (!strcmp(name, "OMX.google.g711.alaw.decoder")) { 47 mIsMLaw = false; 48 } else { 49 CHECK(!strcmp(name, "OMX.google.g711.mlaw.decoder")); 50 } 51 52 initPorts(); 53} 54 55SoftG711::~SoftG711() { 56} 57 58void SoftG711::initPorts() { 59 OMX_PARAM_PORTDEFINITIONTYPE def; 60 InitOMXParams(&def); 61 62 def.nPortIndex = 0; 63 def.eDir = OMX_DirInput; 64 def.nBufferCountMin = kNumBuffers; 65 def.nBufferCountActual = def.nBufferCountMin; 66 def.nBufferSize = 8192; 67 def.bEnabled = OMX_TRUE; 68 def.bPopulated = OMX_FALSE; 69 def.eDomain = OMX_PortDomainAudio; 70 def.bBuffersContiguous = OMX_FALSE; 71 def.nBufferAlignment = 1; 72 73 def.format.audio.cMIMEType = 74 const_cast<char *>( 75 mIsMLaw 76 ? MEDIA_MIMETYPE_AUDIO_G711_MLAW 77 : MEDIA_MIMETYPE_AUDIO_G711_ALAW); 78 79 def.format.audio.pNativeRender = NULL; 80 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 81 def.format.audio.eEncoding = OMX_AUDIO_CodingG711; 82 83 addPort(def); 84 85 def.nPortIndex = 1; 86 def.eDir = OMX_DirOutput; 87 def.nBufferCountMin = kNumBuffers; 88 def.nBufferCountActual = def.nBufferCountMin; 89 def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t); 90 def.bEnabled = OMX_TRUE; 91 def.bPopulated = OMX_FALSE; 92 def.eDomain = OMX_PortDomainAudio; 93 def.bBuffersContiguous = OMX_FALSE; 94 def.nBufferAlignment = 2; 95 96 def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); 97 def.format.audio.pNativeRender = NULL; 98 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 99 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 100 101 addPort(def); 102} 103 104OMX_ERRORTYPE SoftG711::internalGetParameter( 105 OMX_INDEXTYPE index, OMX_PTR params) { 106 switch (index) { 107 case OMX_IndexParamAudioPcm: 108 { 109 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 110 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 111 112 if (!isValidOMXParam(pcmParams)) { 113 return OMX_ErrorBadParameter; 114 } 115 116 if (pcmParams->nPortIndex > 1) { 117 return OMX_ErrorUndefined; 118 } 119 120 pcmParams->eNumData = OMX_NumericalDataSigned; 121 pcmParams->eEndian = OMX_EndianBig; 122 pcmParams->bInterleaved = OMX_TRUE; 123 pcmParams->nBitPerSample = 16; 124 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 125 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 126 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 127 128 pcmParams->nChannels = mNumChannels; 129 pcmParams->nSamplingRate = 8000; 130 131 return OMX_ErrorNone; 132 } 133 134 default: 135 return SimpleSoftOMXComponent::internalGetParameter(index, params); 136 } 137} 138 139OMX_ERRORTYPE SoftG711::internalSetParameter( 140 OMX_INDEXTYPE index, const OMX_PTR params) { 141 switch (index) { 142 case OMX_IndexParamAudioPcm: 143 { 144 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 145 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 146 147 if (!isValidOMXParam(pcmParams)) { 148 return OMX_ErrorBadParameter; 149 } 150 151 if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) { 152 return OMX_ErrorUndefined; 153 } 154 155 if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) { 156 return OMX_ErrorUndefined; 157 } 158 159 if(pcmParams->nPortIndex == 0) { 160 mNumChannels = pcmParams->nChannels; 161 } 162 163 return OMX_ErrorNone; 164 } 165 166 case OMX_IndexParamStandardComponentRole: 167 { 168 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 169 (const OMX_PARAM_COMPONENTROLETYPE *)params; 170 171 if (!isValidOMXParam(roleParams)) { 172 return OMX_ErrorBadParameter; 173 } 174 175 if (mIsMLaw) { 176 if (strncmp((const char *)roleParams->cRole, 177 "audio_decoder.g711mlaw", 178 OMX_MAX_STRINGNAME_SIZE - 1)) { 179 return OMX_ErrorUndefined; 180 } 181 } else { 182 if (strncmp((const char *)roleParams->cRole, 183 "audio_decoder.g711alaw", 184 OMX_MAX_STRINGNAME_SIZE - 1)) { 185 return OMX_ErrorUndefined; 186 } 187 } 188 189 return OMX_ErrorNone; 190 } 191 192 default: 193 return SimpleSoftOMXComponent::internalSetParameter(index, params); 194 } 195} 196 197void SoftG711::onQueueFilled(OMX_U32 portIndex) { 198 if (mSignalledError) { 199 return; 200 } 201 202 List<BufferInfo *> &inQueue = getPortQueue(0); 203 List<BufferInfo *> &outQueue = getPortQueue(1); 204 205 while (!inQueue.empty() && !outQueue.empty()) { 206 BufferInfo *inInfo = *inQueue.begin(); 207 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 208 209 BufferInfo *outInfo = *outQueue.begin(); 210 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 211 212 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 213 inQueue.erase(inQueue.begin()); 214 inInfo->mOwnedByUs = false; 215 notifyEmptyBufferDone(inHeader); 216 217 outHeader->nFilledLen = 0; 218 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 219 220 outQueue.erase(outQueue.begin()); 221 outInfo->mOwnedByUs = false; 222 notifyFillBufferDone(outHeader); 223 return; 224 } 225 226 if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { 227 ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); 228 229 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 230 mSignalledError = true; 231 } 232 233 if (inHeader->nFilledLen * sizeof(int16_t) > outHeader->nAllocLen) { 234 ALOGE("output buffer too small (%d).", outHeader->nAllocLen); 235 android_errorWriteLog(0x534e4554, "27793163"); 236 237 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 238 mSignalledError = true; 239 return; 240 } 241 242 const uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset; 243 244 if (mIsMLaw) { 245 DecodeMLaw( 246 reinterpret_cast<int16_t *>(outHeader->pBuffer), 247 inputptr, inHeader->nFilledLen); 248 } else { 249 DecodeALaw( 250 reinterpret_cast<int16_t *>(outHeader->pBuffer), 251 inputptr, inHeader->nFilledLen); 252 } 253 254 outHeader->nTimeStamp = inHeader->nTimeStamp; 255 outHeader->nOffset = 0; 256 outHeader->nFilledLen = inHeader->nFilledLen * sizeof(int16_t); 257 outHeader->nFlags = 0; 258 259 inInfo->mOwnedByUs = false; 260 inQueue.erase(inQueue.begin()); 261 inInfo = NULL; 262 notifyEmptyBufferDone(inHeader); 263 inHeader = NULL; 264 265 outInfo->mOwnedByUs = false; 266 outQueue.erase(outQueue.begin()); 267 outInfo = NULL; 268 notifyFillBufferDone(outHeader); 269 outHeader = NULL; 270 } 271} 272 273// static 274void SoftG711::DecodeALaw( 275 int16_t *out, const uint8_t *in, size_t inSize) { 276 while (inSize-- > 0) { 277 int32_t x = *in++; 278 279 int32_t ix = x ^ 0x55; 280 ix &= 0x7f; 281 282 int32_t iexp = ix >> 4; 283 int32_t mant = ix & 0x0f; 284 285 if (iexp > 0) { 286 mant += 16; 287 } 288 289 mant = (mant << 4) + 8; 290 291 if (iexp > 1) { 292 mant = mant << (iexp - 1); 293 } 294 295 *out++ = (x > 127) ? mant : -mant; 296 } 297} 298 299// static 300void SoftG711::DecodeMLaw( 301 int16_t *out, const uint8_t *in, size_t inSize) { 302 while (inSize-- > 0) { 303 int32_t x = *in++; 304 305 int32_t mantissa = ~x; 306 int32_t exponent = (mantissa >> 4) & 7; 307 int32_t segment = exponent + 1; 308 mantissa &= 0x0f; 309 310 int32_t step = 4 << segment; 311 312 int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33; 313 314 *out++ = (x < 0x80) ? -abs : abs; 315 } 316} 317 318} // namespace android 319 320android::SoftOMXComponent *createSoftOMXComponent( 321 const char *name, const OMX_CALLBACKTYPE *callbacks, 322 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 323 return new android::SoftG711(name, callbacks, appData, component); 324} 325 326