1/* 2 * Copyright (C) 2012 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 "SoftAMRWBEncoder" 19#include <utils/Log.h> 20 21#include "SoftAMRWBEncoder.h" 22 23#include "cmnMemory.h" 24 25#include <media/stagefright/foundation/ADebug.h> 26#include <media/stagefright/foundation/hexdump.h> 27 28namespace android { 29 30static const int32_t kSampleRate = 16000; 31 32template<class T> 33static void InitOMXParams(T *params) { 34 params->nSize = sizeof(T); 35 params->nVersion.s.nVersionMajor = 1; 36 params->nVersion.s.nVersionMinor = 0; 37 params->nVersion.s.nRevision = 0; 38 params->nVersion.s.nStep = 0; 39} 40 41SoftAMRWBEncoder::SoftAMRWBEncoder( 42 const char *name, 43 const OMX_CALLBACKTYPE *callbacks, 44 OMX_PTR appData, 45 OMX_COMPONENTTYPE **component) 46 : SimpleSoftOMXComponent(name, callbacks, appData, component), 47 mEncoderHandle(NULL), 48 mApiHandle(NULL), 49 mMemOperator(NULL), 50 mBitRate(0), 51 mMode(VOAMRWB_MD66), 52 mInputSize(0), 53 mInputTimeUs(-1ll), 54 mSawInputEOS(false), 55 mSignalledError(false) { 56 initPorts(); 57 CHECK_EQ(initEncoder(), (status_t)OK); 58} 59 60SoftAMRWBEncoder::~SoftAMRWBEncoder() { 61 if (mEncoderHandle != NULL) { 62 CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); 63 mEncoderHandle = NULL; 64 } 65 66 delete mApiHandle; 67 mApiHandle = NULL; 68 69 delete mMemOperator; 70 mMemOperator = NULL; 71} 72 73void SoftAMRWBEncoder::initPorts() { 74 OMX_PARAM_PORTDEFINITIONTYPE def; 75 InitOMXParams(&def); 76 77 def.nPortIndex = 0; 78 def.eDir = OMX_DirInput; 79 def.nBufferCountMin = kNumBuffers; 80 def.nBufferCountActual = def.nBufferCountMin; 81 def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); 82 def.bEnabled = OMX_TRUE; 83 def.bPopulated = OMX_FALSE; 84 def.eDomain = OMX_PortDomainAudio; 85 def.bBuffersContiguous = OMX_FALSE; 86 def.nBufferAlignment = 1; 87 88 def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); 89 def.format.audio.pNativeRender = NULL; 90 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 91 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 92 93 addPort(def); 94 95 def.nPortIndex = 1; 96 def.eDir = OMX_DirOutput; 97 def.nBufferCountMin = kNumBuffers; 98 def.nBufferCountActual = def.nBufferCountMin; 99 def.nBufferSize = 8192; 100 def.bEnabled = OMX_TRUE; 101 def.bPopulated = OMX_FALSE; 102 def.eDomain = OMX_PortDomainAudio; 103 def.bBuffersContiguous = OMX_FALSE; 104 def.nBufferAlignment = 2; 105 106 def.format.audio.cMIMEType = const_cast<char *>("audio/amr-wb"); 107 def.format.audio.pNativeRender = NULL; 108 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 109 def.format.audio.eEncoding = OMX_AUDIO_CodingAMR; 110 111 addPort(def); 112} 113 114status_t SoftAMRWBEncoder::initEncoder() { 115 mApiHandle = new VO_AUDIO_CODECAPI; 116 117 if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) { 118 ALOGE("Failed to get api handle"); 119 return UNKNOWN_ERROR; 120 } 121 122 mMemOperator = new VO_MEM_OPERATOR; 123 mMemOperator->Alloc = cmnMemAlloc; 124 mMemOperator->Copy = cmnMemCopy; 125 mMemOperator->Free = cmnMemFree; 126 mMemOperator->Set = cmnMemSet; 127 mMemOperator->Check = cmnMemCheck; 128 129 VO_CODEC_INIT_USERDATA userData; 130 memset(&userData, 0, sizeof(userData)); 131 userData.memflag = VO_IMF_USERMEMOPERATOR; 132 userData.memData = (VO_PTR) mMemOperator; 133 134 if (VO_ERR_NONE != mApiHandle->Init( 135 &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) { 136 ALOGE("Failed to init AMRWB encoder"); 137 return UNKNOWN_ERROR; 138 } 139 140 VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267; 141 if (VO_ERR_NONE != mApiHandle->SetParam( 142 mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) { 143 ALOGE("Failed to set AMRWB encoder frame type to %d", type); 144 return UNKNOWN_ERROR; 145 } 146 147 return OK; 148} 149 150OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter( 151 OMX_INDEXTYPE index, OMX_PTR params) { 152 switch (index) { 153 case OMX_IndexParamAudioPortFormat: 154 { 155 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 156 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 157 158 if (!isValidOMXParam(formatParams)) { 159 return OMX_ErrorBadParameter; 160 } 161 162 if (formatParams->nPortIndex > 1) { 163 return OMX_ErrorUndefined; 164 } 165 166 if (formatParams->nIndex > 0) { 167 return OMX_ErrorNoMore; 168 } 169 170 formatParams->eEncoding = 171 (formatParams->nPortIndex == 0) 172 ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR; 173 174 return OMX_ErrorNone; 175 } 176 177 case OMX_IndexParamAudioAmr: 178 { 179 OMX_AUDIO_PARAM_AMRTYPE *amrParams = 180 (OMX_AUDIO_PARAM_AMRTYPE *)params; 181 182 if (!isValidOMXParam(amrParams)) { 183 return OMX_ErrorBadParameter; 184 } 185 186 if (amrParams->nPortIndex != 1) { 187 return OMX_ErrorUndefined; 188 } 189 190 amrParams->nChannels = 1; 191 amrParams->nBitRate = mBitRate; 192 193 amrParams->eAMRBandMode = 194 (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0); 195 196 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; 197 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; 198 199 return OMX_ErrorNone; 200 } 201 202 case OMX_IndexParamAudioPcm: 203 { 204 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 205 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 206 207 if (!isValidOMXParam(pcmParams)) { 208 return OMX_ErrorBadParameter; 209 } 210 211 if (pcmParams->nPortIndex != 0) { 212 return OMX_ErrorUndefined; 213 } 214 215 pcmParams->eNumData = OMX_NumericalDataSigned; 216 pcmParams->eEndian = OMX_EndianBig; 217 pcmParams->bInterleaved = OMX_TRUE; 218 pcmParams->nBitPerSample = 16; 219 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 220 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF; 221 222 pcmParams->nChannels = 1; 223 pcmParams->nSamplingRate = kSampleRate; 224 225 return OMX_ErrorNone; 226 } 227 228 default: 229 return SimpleSoftOMXComponent::internalGetParameter(index, params); 230 } 231} 232 233OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter( 234 OMX_INDEXTYPE index, const OMX_PTR params) { 235 switch (index) { 236 case OMX_IndexParamStandardComponentRole: 237 { 238 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 239 (const OMX_PARAM_COMPONENTROLETYPE *)params; 240 241 if (!isValidOMXParam(roleParams)) { 242 return OMX_ErrorBadParameter; 243 } 244 245 if (strncmp((const char *)roleParams->cRole, 246 "audio_encoder.amrwb", 247 OMX_MAX_STRINGNAME_SIZE - 1)) { 248 return OMX_ErrorUndefined; 249 } 250 251 return OMX_ErrorNone; 252 } 253 254 case OMX_IndexParamAudioPortFormat: 255 { 256 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 257 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 258 259 if (!isValidOMXParam(formatParams)) { 260 return OMX_ErrorBadParameter; 261 } 262 263 if (formatParams->nPortIndex > 1) { 264 return OMX_ErrorUndefined; 265 } 266 267 if (formatParams->nIndex > 0) { 268 return OMX_ErrorNoMore; 269 } 270 271 if ((formatParams->nPortIndex == 0 272 && formatParams->eEncoding != OMX_AUDIO_CodingPCM) 273 || (formatParams->nPortIndex == 1 274 && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) { 275 return OMX_ErrorUndefined; 276 } 277 278 return OMX_ErrorNone; 279 } 280 281 case OMX_IndexParamAudioAmr: 282 { 283 OMX_AUDIO_PARAM_AMRTYPE *amrParams = 284 (OMX_AUDIO_PARAM_AMRTYPE *)params; 285 286 if (!isValidOMXParam(amrParams)) { 287 return OMX_ErrorBadParameter; 288 } 289 290 if (amrParams->nPortIndex != 1) { 291 return OMX_ErrorUndefined; 292 } 293 294 if (amrParams->nChannels != 1 295 || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff 296 || amrParams->eAMRFrameFormat 297 != OMX_AUDIO_AMRFrameFormatFSF 298 || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0 299 || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) { 300 return OMX_ErrorUndefined; 301 } 302 303 mBitRate = amrParams->nBitRate; 304 305 mMode = (VOAMRWBMODE)( 306 amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0); 307 308 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; 309 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; 310 311 if (VO_ERR_NONE != 312 mApiHandle->SetParam( 313 mEncoderHandle, VO_PID_AMRWB_MODE, &mMode)) { 314 ALOGE("Failed to set AMRWB encoder mode to %d", mMode); 315 return OMX_ErrorUndefined; 316 } 317 318 return OMX_ErrorNone; 319 } 320 321 case OMX_IndexParamAudioPcm: 322 { 323 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 324 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 325 326 if (!isValidOMXParam(pcmParams)) { 327 return OMX_ErrorBadParameter; 328 } 329 330 if (pcmParams->nPortIndex != 0) { 331 return OMX_ErrorUndefined; 332 } 333 334 if (pcmParams->nChannels != 1 335 || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) { 336 return OMX_ErrorUndefined; 337 } 338 339 return OMX_ErrorNone; 340 } 341 342 343 default: 344 return SimpleSoftOMXComponent::internalSetParameter(index, params); 345 } 346} 347 348void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { 349 if (mSignalledError) { 350 return; 351 } 352 353 List<BufferInfo *> &inQueue = getPortQueue(0); 354 List<BufferInfo *> &outQueue = getPortQueue(1); 355 356 size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t); 357 358 for (;;) { 359 // We do the following until we run out of buffers. 360 361 while (mInputSize < numBytesPerInputFrame) { 362 // As long as there's still input data to be read we 363 // will drain "kNumSamplesPerFrame" samples 364 // into the "mInputFrame" buffer and then encode those 365 // as a unit into an output buffer. 366 367 if (mSawInputEOS || inQueue.empty()) { 368 return; 369 } 370 371 BufferInfo *inInfo = *inQueue.begin(); 372 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 373 374 const void *inData = inHeader->pBuffer + inHeader->nOffset; 375 376 size_t copy = numBytesPerInputFrame - mInputSize; 377 if (copy > inHeader->nFilledLen) { 378 copy = inHeader->nFilledLen; 379 } 380 381 if (mInputSize == 0) { 382 mInputTimeUs = inHeader->nTimeStamp; 383 } 384 385 memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); 386 mInputSize += copy; 387 388 inHeader->nOffset += copy; 389 inHeader->nFilledLen -= copy; 390 391 // "Time" on the input buffer has in effect advanced by the 392 // number of audio frames we just advanced nOffset by. 393 inHeader->nTimeStamp += 394 (copy * 1000000ll / kSampleRate) / sizeof(int16_t); 395 396 if (inHeader->nFilledLen == 0) { 397 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 398 ALOGV("saw input EOS"); 399 mSawInputEOS = true; 400 401 // Pad any remaining data with zeroes. 402 memset((uint8_t *)mInputFrame + mInputSize, 403 0, 404 numBytesPerInputFrame - mInputSize); 405 406 mInputSize = numBytesPerInputFrame; 407 } 408 409 inQueue.erase(inQueue.begin()); 410 inInfo->mOwnedByUs = false; 411 notifyEmptyBufferDone(inHeader); 412 413 inData = NULL; 414 inHeader = NULL; 415 inInfo = NULL; 416 } 417 } 418 419 // At this point we have all the input data necessary to encode 420 // a single frame, all we need is an output buffer to store the result 421 // in. 422 423 if (outQueue.empty()) { 424 return; 425 } 426 427 BufferInfo *outInfo = *outQueue.begin(); 428 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 429 430 uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset; 431 size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; 432 433 VO_CODECBUFFER inputData; 434 memset(&inputData, 0, sizeof(inputData)); 435 inputData.Buffer = (unsigned char *) mInputFrame; 436 inputData.Length = mInputSize; 437 438 CHECK_EQ(VO_ERR_NONE, 439 mApiHandle->SetInputData(mEncoderHandle, &inputData)); 440 441 VO_CODECBUFFER outputData; 442 memset(&outputData, 0, sizeof(outputData)); 443 VO_AUDIO_OUTPUTINFO outputInfo; 444 memset(&outputInfo, 0, sizeof(outputInfo)); 445 446 outputData.Buffer = outPtr; 447 outputData.Length = outAvailable; 448 VO_U32 ret = mApiHandle->GetOutputData( 449 mEncoderHandle, &outputData, &outputInfo); 450 CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL); 451 452 outHeader->nFilledLen = outputData.Length; 453 outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; 454 455 if (mSawInputEOS) { 456 // We also tag this output buffer with EOS if it corresponds 457 // to the final input buffer. 458 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 459 } 460 461 outHeader->nTimeStamp = mInputTimeUs; 462 463#if 0 464 ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)", 465 outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags); 466 467 hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); 468#endif 469 470 outQueue.erase(outQueue.begin()); 471 outInfo->mOwnedByUs = false; 472 notifyFillBufferDone(outHeader); 473 474 outHeader = NULL; 475 outInfo = NULL; 476 477 mInputSize = 0; 478 } 479} 480 481} // namespace android 482 483android::SoftOMXComponent *createSoftOMXComponent( 484 const char *name, const OMX_CALLBACKTYPE *callbacks, 485 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 486 return new android::SoftAMRWBEncoder(name, callbacks, appData, component); 487} 488