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 mSignalledError(false), 45 mNumChannels(1), 46 mSamplingRate(8000) { 47 if (!strcmp(name, "OMX.google.g711.alaw.decoder")) { 48 mIsMLaw = false; 49 } else { 50 CHECK(!strcmp(name, "OMX.google.g711.mlaw.decoder")); 51 } 52 53 initPorts(); 54} 55 56SoftG711::~SoftG711() { 57} 58 59void SoftG711::initPorts() { 60 OMX_PARAM_PORTDEFINITIONTYPE def; 61 InitOMXParams(&def); 62 63 def.nPortIndex = 0; 64 def.eDir = OMX_DirInput; 65 def.nBufferCountMin = kNumBuffers; 66 def.nBufferCountActual = def.nBufferCountMin; 67 def.nBufferSize = 8192; 68 def.bEnabled = OMX_TRUE; 69 def.bPopulated = OMX_FALSE; 70 def.eDomain = OMX_PortDomainAudio; 71 def.bBuffersContiguous = OMX_FALSE; 72 def.nBufferAlignment = 1; 73 74 def.format.audio.cMIMEType = 75 const_cast<char *>( 76 mIsMLaw 77 ? MEDIA_MIMETYPE_AUDIO_G711_MLAW 78 : MEDIA_MIMETYPE_AUDIO_G711_ALAW); 79 80 def.format.audio.pNativeRender = NULL; 81 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 82 def.format.audio.eEncoding = OMX_AUDIO_CodingG711; 83 84 addPort(def); 85 86 def.nPortIndex = 1; 87 def.eDir = OMX_DirOutput; 88 def.nBufferCountMin = kNumBuffers; 89 def.nBufferCountActual = def.nBufferCountMin; 90 def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t); 91 def.bEnabled = OMX_TRUE; 92 def.bPopulated = OMX_FALSE; 93 def.eDomain = OMX_PortDomainAudio; 94 def.bBuffersContiguous = OMX_FALSE; 95 def.nBufferAlignment = 2; 96 97 def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); 98 def.format.audio.pNativeRender = NULL; 99 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 100 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 101 102 addPort(def); 103} 104 105OMX_ERRORTYPE SoftG711::internalGetParameter( 106 OMX_INDEXTYPE index, OMX_PTR params) { 107 switch (index) { 108 case OMX_IndexParamAudioPortFormat: 109 { 110 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 111 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 112 113 if (!isValidOMXParam(formatParams)) { 114 return OMX_ErrorBadParameter; 115 } 116 117 if (formatParams->nPortIndex > 1) { 118 return OMX_ErrorUndefined; 119 } 120 121 if (formatParams->nIndex > 0) { 122 return OMX_ErrorNoMore; 123 } 124 125 formatParams->eEncoding = 126 (formatParams->nPortIndex == 0) 127 ? OMX_AUDIO_CodingG711 : OMX_AUDIO_CodingPCM; 128 129 return OMX_ErrorNone; 130 } 131 132 case OMX_IndexParamAudioPcm: 133 { 134 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 135 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 136 137 if (!isValidOMXParam(pcmParams)) { 138 return OMX_ErrorBadParameter; 139 } 140 141 if (pcmParams->nPortIndex > 1) { 142 return OMX_ErrorUndefined; 143 } 144 145 pcmParams->eNumData = OMX_NumericalDataSigned; 146 pcmParams->eEndian = OMX_EndianBig; 147 pcmParams->bInterleaved = OMX_TRUE; 148 pcmParams->nBitPerSample = 16; 149 if (pcmParams->nPortIndex == 0) { 150 // input port 151 pcmParams->ePCMMode = mIsMLaw ? OMX_AUDIO_PCMModeMULaw 152 : OMX_AUDIO_PCMModeALaw; 153 } else { 154 // output port 155 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 156 } 157 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 158 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 159 160 pcmParams->nChannels = mNumChannels; 161 pcmParams->nSamplingRate = mSamplingRate; 162 163 return OMX_ErrorNone; 164 } 165 166 default: 167 return SimpleSoftOMXComponent::internalGetParameter(index, params); 168 } 169} 170 171OMX_ERRORTYPE SoftG711::internalSetParameter( 172 OMX_INDEXTYPE index, const OMX_PTR params) { 173 switch (index) { 174 case OMX_IndexParamAudioPcm: 175 { 176 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 177 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 178 179 if (!isValidOMXParam(pcmParams)) { 180 return OMX_ErrorBadParameter; 181 } 182 183 if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) { 184 return OMX_ErrorUndefined; 185 } 186 187 if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) { 188 return OMX_ErrorUndefined; 189 } 190 191 if(pcmParams->nPortIndex == 0) { 192 mNumChannels = pcmParams->nChannels; 193 } 194 195 mSamplingRate = pcmParams->nSamplingRate; 196 197 return OMX_ErrorNone; 198 } 199 200 case OMX_IndexParamAudioPortFormat: 201 { 202 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 203 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 204 205 if (!isValidOMXParam(formatParams)) { 206 return OMX_ErrorBadParameter; 207 } 208 209 if (formatParams->nPortIndex > 1) { 210 return OMX_ErrorUndefined; 211 } 212 213 if ((formatParams->nPortIndex == 0 214 && formatParams->eEncoding != OMX_AUDIO_CodingG711) 215 || (formatParams->nPortIndex == 1 216 && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { 217 return OMX_ErrorUndefined; 218 } 219 220 return OMX_ErrorNone; 221 } 222 223 case OMX_IndexParamStandardComponentRole: 224 { 225 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 226 (const OMX_PARAM_COMPONENTROLETYPE *)params; 227 228 if (!isValidOMXParam(roleParams)) { 229 return OMX_ErrorBadParameter; 230 } 231 232 if (mIsMLaw) { 233 if (strncmp((const char *)roleParams->cRole, 234 "audio_decoder.g711mlaw", 235 OMX_MAX_STRINGNAME_SIZE - 1)) { 236 return OMX_ErrorUndefined; 237 } 238 } else { 239 if (strncmp((const char *)roleParams->cRole, 240 "audio_decoder.g711alaw", 241 OMX_MAX_STRINGNAME_SIZE - 1)) { 242 return OMX_ErrorUndefined; 243 } 244 } 245 246 return OMX_ErrorNone; 247 } 248 249 default: 250 return SimpleSoftOMXComponent::internalSetParameter(index, params); 251 } 252} 253 254void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) { 255 if (mSignalledError) { 256 return; 257 } 258 259 List<BufferInfo *> &inQueue = getPortQueue(0); 260 List<BufferInfo *> &outQueue = getPortQueue(1); 261 262 while (!inQueue.empty() && !outQueue.empty()) { 263 BufferInfo *inInfo = *inQueue.begin(); 264 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 265 266 BufferInfo *outInfo = *outQueue.begin(); 267 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 268 269 if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { 270 inQueue.erase(inQueue.begin()); 271 inInfo->mOwnedByUs = false; 272 notifyEmptyBufferDone(inHeader); 273 274 outHeader->nFilledLen = 0; 275 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 276 277 outQueue.erase(outQueue.begin()); 278 outInfo->mOwnedByUs = false; 279 notifyFillBufferDone(outHeader); 280 return; 281 } 282 283 if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { 284 ALOGE("input buffer too large (%d).", inHeader->nFilledLen); 285 286 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 287 mSignalledError = true; 288 } 289 290 if (inHeader->nFilledLen * sizeof(int16_t) > outHeader->nAllocLen) { 291 ALOGE("output buffer too small (%d).", outHeader->nAllocLen); 292 android_errorWriteLog(0x534e4554, "27793163"); 293 294 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 295 mSignalledError = true; 296 return; 297 } 298 299 const uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset; 300 301 if (mIsMLaw) { 302 DecodeMLaw( 303 reinterpret_cast<int16_t *>(outHeader->pBuffer), 304 inputptr, inHeader->nFilledLen); 305 } else { 306 DecodeALaw( 307 reinterpret_cast<int16_t *>(outHeader->pBuffer), 308 inputptr, inHeader->nFilledLen); 309 } 310 311 outHeader->nTimeStamp = inHeader->nTimeStamp; 312 outHeader->nOffset = 0; 313 outHeader->nFilledLen = inHeader->nFilledLen * sizeof(int16_t); 314 outHeader->nFlags = 0; 315 316 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 317 inHeader->nFilledLen = 0; 318 } else { 319 inInfo->mOwnedByUs = false; 320 inQueue.erase(inQueue.begin()); 321 inInfo = NULL; 322 notifyEmptyBufferDone(inHeader); 323 inHeader = NULL; 324 } 325 326 outInfo->mOwnedByUs = false; 327 outQueue.erase(outQueue.begin()); 328 outInfo = NULL; 329 notifyFillBufferDone(outHeader); 330 outHeader = NULL; 331 } 332} 333 334// static 335void SoftG711::DecodeALaw( 336 int16_t *out, const uint8_t *in, size_t inSize) { 337 while (inSize > 0) { 338 inSize--; 339 int32_t x = *in++; 340 341 int32_t ix = x ^ 0x55; 342 ix &= 0x7f; 343 344 int32_t iexp = ix >> 4; 345 int32_t mant = ix & 0x0f; 346 347 if (iexp > 0) { 348 mant += 16; 349 } 350 351 mant = (mant << 4) + 8; 352 353 if (iexp > 1) { 354 mant = mant << (iexp - 1); 355 } 356 357 *out++ = (x > 127) ? mant : -mant; 358 } 359} 360 361// static 362void SoftG711::DecodeMLaw( 363 int16_t *out, const uint8_t *in, size_t inSize) { 364 while (inSize > 0) { 365 inSize--; 366 int32_t x = *in++; 367 368 int32_t mantissa = ~x; 369 int32_t exponent = (mantissa >> 4) & 7; 370 int32_t segment = exponent + 1; 371 mantissa &= 0x0f; 372 373 int32_t step = 4 << segment; 374 375 int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33; 376 377 *out++ = (x < 0x80) ? -abs : abs; 378 } 379} 380 381} // namespace android 382 383android::SoftOMXComponent *createSoftOMXComponent( 384 const char *name, const OMX_CALLBACKTYPE *callbacks, 385 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 386 return new android::SoftG711(name, callbacks, appData, component); 387} 388 389