slesTestDecodeAac.cpp revision 5760ef34bd7f50060fd8fbda10e359f8a830bfbc
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/* AAC ADTS Decode Test 18 19First run the program from shell: 20 # slesTestDecodeAac /sdcard/myFile.adts 21 22Expected output: 23 OpenSL ES test slesTestDecodeAac: decodes a file containing AAC ADTS data 24 Player created 25 Player realized 26 Enqueueing initial empty buffers to receive decoded PCM data 0 1 27 Enqueueing initial full buffers of encoded ADTS data 0 1 28 Starting to decode 29 Frame counters: encoded=4579 decoded=4579 30 31These use adb on host to retrieve the decoded file: 32 % adb pull /sdcard/myFile.adts.raw myFile.raw 33 34How to examine the output with Audacity: 35 Project / Import raw data 36 Select myFile.raw file, then click Open button 37 Choose these options: 38 Signed 16-bit PCM 39 Little-endian 40 1 Channel (Mono) / 2 Channels (Stereo) based on the PCM information obtained when decoding 41 Sample rate based on the PCM information obtained when decoding 42 Click Import button 43 44*/ 45 46#define QUERY_METADATA 47 48#include <stdlib.h> 49#include <stdio.h> 50#include <string.h> 51#include <unistd.h> 52#include <sys/time.h> 53#include <fcntl.h> 54#include <pthread.h> 55#include <sys/mman.h> 56#include <sys/stat.h> 57#include <unistd.h> 58 59#include <SLES/OpenSLES.h> 60#include <SLES/OpenSLES_Android.h> 61 62/* Explicitly requesting SL_IID_ANDROIDBUFFERQUEUE and SL_IID_ANDROIDSIMPLEBUFFERQUEUE 63 * on the AudioPlayer object for decoding, and 64 * SL_IID_METADATAEXTRACTION for retrieving the format of the decoded audio. 65 */ 66#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 3 67 68/* Number of decoded samples produced by one AAC frame; defined by the standard */ 69#define SAMPLES_PER_AAC_FRAME 1024 70/* Size of the encoded AAC ADTS buffer queue */ 71#define NB_BUFFERS_IN_ADTS_QUEUE 2 // 2 to 4 is typical 72 73/* Size of the decoded PCM buffer queue */ 74#define NB_BUFFERS_IN_PCM_QUEUE 2 // 2 to 4 is typical 75/* Size of each PCM buffer in the queue */ 76#define BUFFER_SIZE_IN_BYTES (2*sizeof(short)*SAMPLES_PER_AAC_FRAME) 77 78/* Local storage for decoded PCM audio data */ 79int8_t pcmData[NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES]; 80 81/* destination for decoded data */ 82static FILE* outputFp; 83 84#ifdef QUERY_METADATA 85/* metadata key index for the PCM format information we want to retrieve */ 86static int channelCountKeyIndex = -1; 87static int sampleRateKeyIndex = -1; 88static int bitsPerSampleKeyIndex = -1; 89static int containerSizeKeyIndex = -1; 90static int channelMaskKeyIndex = -1; 91static int endiannessKeyIndex = -1; 92/* size of the struct to retrieve the PCM format metadata values: the values we're interested in 93 * are SLuint32, but it is saved in the data field of a SLMetadataInfo, hence the larger size. 94 * Note that this size is queried and displayed at l.XXX for demonstration/test purposes. 95 * */ 96#define PCM_METADATA_VALUE_SIZE 32 97/* used to query metadata values */ 98static SLMetadataInfo *pcmMetaData = NULL; 99/* we only want to query / display the PCM format once */ 100static bool formatQueried = false; 101#endif 102 103/* to signal to the test app that the end of the encoded ADTS stream has been reached */ 104bool eos = false; 105bool endOfEncodedStream = false; 106 107void *ptr; 108unsigned char *frame; 109size_t filelen; 110size_t encodedFrames = 0; 111size_t encodedSamples = 0; 112size_t decodedFrames = 0; 113size_t decodedSamples = 0; 114 115/* constant to identify a buffer context which is the end of the stream to decode */ 116static const int kEosBufferCntxt = 1980; // a magic value we can compare against 117 118/* protects shared variables */ 119pthread_mutex_t eosLock = PTHREAD_MUTEX_INITIALIZER; 120pthread_cond_t eosCondition = PTHREAD_COND_INITIALIZER; 121 122//----------------------------------------------------------------- 123/* Exits the application if an error is encountered */ 124#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 125 126void ExitOnErrorFunc( SLresult result , int line) 127{ 128 if (SL_RESULT_SUCCESS != result) { 129 fprintf(stderr, "Error code %u encountered at line %d, exiting\n", result, line); 130 exit(EXIT_FAILURE); 131 } 132} 133 134//----------------------------------------------------------------- 135/* Structure for passing information to callback function */ 136typedef struct CallbackCntxt_ { 137#ifdef QUERY_METADATA 138 SLMetadataExtractionItf metaItf; 139#endif 140 SLPlayItf playItf; 141 SLint8* pDataBase; // Base address of local audio data storage 142 SLint8* pData; // Current address of local audio data storage 143} CallbackCntxt; 144 145//----------------------------------------------------------------- 146/* Callback for AndroidBufferQueueItf through which we supply ADTS buffers */ 147SLresult AndroidBufferQueueCallback( 148 SLAndroidBufferQueueItf caller, 149 void *pCallbackContext, /* input */ 150 void *pBufferContext, /* input */ 151 void *pBufferData, /* input */ 152 SLuint32 dataSize, /* input */ 153 SLuint32 dataUsed, /* input */ 154 const SLAndroidBufferItem *pItems,/* input */ 155 SLuint32 itemsLength /* input */) 156{ 157 // mutex on all global variables 158 pthread_mutex_lock(&eosLock); 159 SLresult res; 160 161 // for demonstration purposes: 162 // verify what type of information was enclosed in the processed buffer 163 if (NULL != pBufferContext) { 164 const int processedCommand = *(int *)pBufferContext; 165 if (kEosBufferCntxt == processedCommand) { 166 fprintf(stdout, "EOS was processed\n"); 167 } 168 } 169 170 if (endOfEncodedStream) { 171 // we continue to receive acknowledgement after each buffer was processed 172 } else if (filelen == 0) { 173 // signal EOS to the decoder rather than just starving it 174 SLAndroidBufferItem msgEos; 175 msgEos.itemKey = SL_ANDROID_ITEMKEY_EOS; 176 msgEos.itemSize = 0; 177 // EOS message has no parameters, so the total size of the message is the size of the key 178 // plus the size of itemSize, both SLuint32 179 res = (*caller)->Enqueue(caller, (void *)&kEosBufferCntxt /*pBufferContext*/, 180 NULL /*pData*/, 0 /*dataLength*/, 181 &msgEos /*pMsg*/, 182 sizeof(SLuint32)*2 /*msgLength*/); 183 ExitOnError(res); 184 endOfEncodedStream = true; 185 // verify that we are at start of an ADTS frame 186 } else if (!(filelen < 7 || frame[0] != 0xFF || (frame[1] & 0xF0) != 0xF0)) { 187 unsigned framelen = ((frame[3] & 3) << 11) | (frame[4] << 3) | (frame[5] >> 5); 188 if (framelen <= filelen) { 189 // push more data to the queue 190 res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 191 frame, framelen, NULL, 0); 192 ExitOnError(res); 193 frame += framelen; 194 filelen -= framelen; 195 ++encodedFrames; 196 encodedSamples += SAMPLES_PER_AAC_FRAME; 197 } else { 198 fprintf(stderr, 199 "partial ADTS frame at EOF discarded; offset=%u, framelen=%u, filelen=%u\n", 200 frame - (unsigned char *) ptr, framelen, filelen); 201 frame += filelen; 202 filelen = 0; 203 } 204 } else { 205 fprintf(stderr, "corrupt ADTS frame encountered; offset=%u, filelen=%u\n", 206 frame - (unsigned char *) ptr, filelen); 207 frame += filelen; 208 filelen = 0; 209 } 210 pthread_mutex_unlock(&eosLock); 211 212 return SL_RESULT_SUCCESS; 213} 214 215//----------------------------------------------------------------- 216/* Callback for decoding buffer queue events */ 217void DecPlayCallback( 218 SLAndroidSimpleBufferQueueItf queueItf, 219 void *pContext) 220{ 221 // mutex on all global variables 222 pthread_mutex_lock(&eosLock); 223 224 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 225 226 /* Save the decoded data to output file */ 227 if (fwrite(pCntxt->pData, 1, BUFFER_SIZE_IN_BYTES, outputFp) < BUFFER_SIZE_IN_BYTES) { 228 fprintf(stderr, "Error writing to output file"); 229 } 230 231 /* Re-enqueue the now empty buffer */ 232 SLresult res; 233 res = (*queueItf)->Enqueue(queueItf, pCntxt->pData, BUFFER_SIZE_IN_BYTES); 234 ExitOnError(res); 235 236 /* Increase data pointer by buffer size, with circular wraparound */ 237 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 238 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES)) { 239 pCntxt->pData = pCntxt->pDataBase; 240 } 241 242 // Note: adding a sleep here or any sync point is a way to slow down the decoding, or 243 // synchronize it with some other event, as the OpenSL ES framework will block until the 244 // buffer queue callback return to proceed with the decoding. 245 246#ifdef QUERY_METADATA 247 /* Example: query of the decoded PCM format */ 248 if (!formatQueried) { 249 /* memory to receive the PCM format metadata */ 250 union { 251 SLMetadataInfo pcmMetaData; 252 char withData[PCM_METADATA_VALUE_SIZE]; 253 } u; 254 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, sampleRateKeyIndex, 255 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 256 // Note: here we could verify the following: 257 // u.pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY 258 // u.pcmMetaData->size == sizeof(SLuint32) 259 // but the call was successful for the PCM format keys, so those conditions are implied 260 printf("sample rate = %d\n", *((SLuint32*)u.pcmMetaData.data)); 261 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelCountKeyIndex, 262 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 263 printf("channel count = %d\n", *((SLuint32*)u.pcmMetaData.data)); 264 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, bitsPerSampleKeyIndex, 265 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 266 printf("bits per sample = %d bits\n", *((SLuint32*)u.pcmMetaData.data)); 267 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, containerSizeKeyIndex, 268 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 269 printf("container size = %d bits\n", *((SLuint32*)u.pcmMetaData.data)); 270 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelMaskKeyIndex, 271 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 272 printf("channel mask = 0x%X (0x3=front left | front right, 0x4=front center)\n", 273 *((SLuint32*)u.pcmMetaData.data)); 274 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, endiannessKeyIndex, 275 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 276 printf("endianness = %d (1=big, 2=little)\n", *((SLuint32*)u.pcmMetaData.data)); 277 formatQueried = true; 278 } 279#endif 280 281 ++decodedFrames; 282 decodedSamples += SAMPLES_PER_AAC_FRAME; 283 284 /* Periodically ask for position and duration */ 285 if ((decodedFrames % 1000 == 0) || endOfEncodedStream) { 286 SLmillisecond position; 287 res = (*pCntxt->playItf)->GetPosition(pCntxt->playItf, &position); 288 ExitOnError(res); 289 SLmillisecond duration; 290 res = (*pCntxt->playItf)->GetDuration(pCntxt->playItf, &duration); 291 ExitOnError(res); 292 if (duration == SL_TIME_UNKNOWN) { 293 printf("After %u decoded frames: position is %u ms, duration is unknown as expected\n", 294 decodedFrames, position); 295 } else { 296 printf("After %u decoded frames: position is %u ms, duration is surprisingly %u ms\n", 297 decodedFrames, position, duration); 298 } 299 } 300 301 if (endOfEncodedStream && decodedSamples >= encodedSamples) { 302 eos = true; 303 pthread_cond_signal(&eosCondition); 304 } 305 pthread_mutex_unlock(&eosLock); 306} 307 308//----------------------------------------------------------------- 309 310/* Decode an audio path by opening a file descriptor on that path */ 311void TestDecToBuffQueue( SLObjectItf sl, const char *path, int fd) 312{ 313 // check what kind of object it is 314 int ok; 315 struct stat statbuf; 316 ok = fstat(fd, &statbuf); 317 if (ok < 0) { 318 perror(path); 319 return; 320 } 321 322 // verify that's it is a file 323 if (!S_ISREG(statbuf.st_mode)) { 324 fprintf(stderr, "%s: not an ordinary file\n", path); 325 return; 326 } 327 328 // map file contents into memory to make it easier to access the ADTS frames directly 329 ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0); 330 if (ptr == MAP_FAILED) { 331 perror(path); 332 return; 333 } 334 frame = (unsigned char *) ptr; 335 filelen = statbuf.st_size; 336 337 // create PCM .raw file 338 size_t len = strlen((const char *) path); 339 char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw" 340 if (NULL == outputPath) { 341 ExitOnError(SL_RESULT_RESOURCE_ERROR); 342 } 343 memcpy(outputPath, path, len + 1); 344 strcat(outputPath, ".raw"); 345 outputFp = fopen(outputPath, "w"); 346 if (NULL == outputFp) { 347 ExitOnError(SL_RESULT_RESOURCE_ERROR); 348 } 349 350 SLresult res; 351 SLEngineItf EngineItf; 352 353 /* Objects this application uses: one audio player */ 354 SLObjectItf player; 355 356 /* Interfaces for the audio player */ 357 SLPlayItf playItf; 358#ifdef QUERY_METADATA 359 /* to retrieve the decoded PCM format */ 360 SLMetadataExtractionItf mdExtrItf; 361#endif 362 /* to retrieve the PCM samples */ 363 SLAndroidSimpleBufferQueueItf decBuffQueueItf; 364 /* to queue the AAC data to decode */ 365 SLAndroidBufferQueueItf aacBuffQueueItf; 366 367 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 368 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 369 370 /* Get the SL Engine Interface which is implicit */ 371 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 372 ExitOnError(res); 373 374 /* Initialize arrays required[] and iidArray[] */ 375 unsigned int i; 376 for (i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) { 377 required[i] = SL_BOOLEAN_FALSE; 378 iidArray[i] = SL_IID_NULL; 379 } 380 381 /* ------------------------------------------------------ */ 382 /* Configuration of the player */ 383 384 /* Request the AndroidSimpleBufferQueue interface */ 385 required[0] = SL_BOOLEAN_TRUE; 386 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 387 /* Request the AndroidBufferQueue interface */ 388 required[1] = SL_BOOLEAN_TRUE; 389 iidArray[1] = SL_IID_ANDROIDBUFFERQUEUE; 390#ifdef QUERY_METADATA 391 /* Request the MetadataExtraction interface */ 392 required[2] = SL_BOOLEAN_TRUE; 393 iidArray[2] = SL_IID_METADATAEXTRACTION; 394#endif 395 396 /* Setup the data source for queueing AAC buffers of ADTS data */ 397 SLDataLocator_AndroidBufferQueue loc_srcAbq = { 398 SL_DATALOCATOR_ANDROIDBUFFERQUEUE /*locatorType*/, 399 NB_BUFFERS_IN_ADTS_QUEUE /*numBuffers*/}; 400 SLDataFormat_MIME format_srcMime = { 401 SL_DATAFORMAT_MIME /*formatType*/, 402 (SLchar *)"audio/aac-adts" /*mimeType*/, 403 SL_CONTAINERTYPE_RAW /*containerType*/}; 404 SLDataSource decSource = {&loc_srcAbq /*pLocator*/, &format_srcMime /*pFormat*/}; 405 406 /* Setup the data sink, a buffer queue for buffers of PCM data */ 407 SLDataLocator_AndroidSimpleBufferQueue loc_destBq = { 408 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE/*locatorType*/, 409 NB_BUFFERS_IN_PCM_QUEUE /*numBuffers*/ }; 410 411 /* declare we're decoding to PCM, the parameters after that need to be valid, 412 but are ignored, the decoded format will match the source */ 413 SLDataFormat_PCM format_destPcm = { /*formatType*/ SL_DATAFORMAT_PCM, /*numChannels*/ 1, 414 /*samplesPerSec*/ SL_SAMPLINGRATE_8, /*pcm.bitsPerSample*/ SL_PCMSAMPLEFORMAT_FIXED_16, 415 /*/containerSize*/ 16, /*channelMask*/ SL_SPEAKER_FRONT_LEFT, 416 /*endianness*/ SL_BYTEORDER_LITTLEENDIAN }; 417 SLDataSink decDest = {&loc_destBq /*pLocator*/, &format_destPcm /*pFormat*/}; 418 419 /* Create the audio player */ 420 res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest, 421#ifdef QUERY_METADATA 422 NUM_EXPLICIT_INTERFACES_FOR_PLAYER, 423#else 424 NUM_EXPLICIT_INTERFACES_FOR_PLAYER - 1, 425#endif 426 iidArray, required); 427 ExitOnError(res); 428 printf("Player created\n"); 429 430 /* Realize the player in synchronous mode. */ 431 res = (*player)->Realize(player, SL_BOOLEAN_FALSE); 432 ExitOnError(res); 433 printf("Player realized\n"); 434 435 /* Get the play interface which is implicit */ 436 res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 437 ExitOnError(res); 438 439 /* Get the position before prefetch; should be zero */ 440 SLmillisecond position; 441 res = (*playItf)->GetPosition(playItf, &position); 442 ExitOnError(res); 443 if (position == 0) { 444 printf("The position before prefetch is zero as expected\n"); 445 } else if (position == SL_TIME_UNKNOWN) { 446 printf("That's surprising the position before prefetch is unknown"); 447 } else { 448 printf("That's surprising the position before prefetch is %u ms\n", position); 449 } 450 451 /* Get the duration before prefetch; should be unknown */ 452 SLmillisecond duration; 453 res = (*playItf)->GetDuration(playItf, &duration); 454 ExitOnError(res); 455 if (duration == SL_TIME_UNKNOWN) { 456 printf("The duration before prefetch is unknown as expected\n"); 457 } else { 458 printf("That's surprising the duration before prefetch is %u ms\n", duration); 459 } 460 461 /* Get the buffer queue interface which was explicitly requested */ 462 res = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void*)&decBuffQueueItf); 463 ExitOnError(res); 464 465 /* Get the Android buffer queue interface which was explicitly requested */ 466 res = (*player)->GetInterface(player, SL_IID_ANDROIDBUFFERQUEUE, (void*)&aacBuffQueueItf); 467 ExitOnError(res); 468 469#ifdef QUERY_METADATA 470 /* Get the metadata extraction interface which was explicitly requested */ 471 res = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void*)&mdExtrItf); 472 ExitOnError(res); 473#endif 474 475 /* ------------------------------------------------------ */ 476 /* Initialize the callback and its context for the buffer queue of the decoded PCM */ 477 CallbackCntxt sinkCntxt; 478 sinkCntxt.playItf = playItf; 479#ifdef QUERY_METADATA 480 sinkCntxt.metaItf = mdExtrItf; 481#endif 482 sinkCntxt.pDataBase = (int8_t*)&pcmData; 483 sinkCntxt.pData = sinkCntxt.pDataBase; 484 res = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecPlayCallback, &sinkCntxt); 485 ExitOnError(res); 486 487 /* Enqueue buffers to map the region of memory allocated to store the decoded data */ 488 printf("Enqueueing initial empty buffers to receive decoded PCM data"); 489 for(i = 0 ; i < NB_BUFFERS_IN_PCM_QUEUE ; i++) { 490 printf(" %d", i); 491 res = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, sinkCntxt.pData, BUFFER_SIZE_IN_BYTES); 492 ExitOnError(res); 493 sinkCntxt.pData += BUFFER_SIZE_IN_BYTES; 494 if (sinkCntxt.pData >= sinkCntxt.pDataBase + 495 (NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES)) { 496 sinkCntxt.pData = sinkCntxt.pDataBase; 497 } 498 } 499 printf("\n"); 500 501 /* Initialize the callback for the Android buffer queue of the encoded data */ 502 res = (*aacBuffQueueItf)->RegisterCallback(aacBuffQueueItf, AndroidBufferQueueCallback, NULL); 503 ExitOnError(res); 504 505 /* Enqueue the content of our encoded data before starting to play, 506 we don't want to starve the player initially */ 507 printf("Enqueueing initial full buffers of encoded ADTS data"); 508 for (i=0 ; i < NB_BUFFERS_IN_ADTS_QUEUE ; i++) { 509 if (filelen < 7 || frame[0] != 0xFF || (frame[1] & 0xF0) != 0xF0) 510 break; 511 unsigned framelen = ((frame[3] & 3) << 11) | (frame[4] << 3) | (frame[5] >> 5); 512 printf(" %d", i); 513 res = (*aacBuffQueueItf)->Enqueue(aacBuffQueueItf, NULL /*pBufferContext*/, 514 frame, framelen, NULL, 0); 515 ExitOnError(res); 516 frame += framelen; 517 filelen -= framelen; 518 ++encodedFrames; 519 encodedSamples += SAMPLES_PER_AAC_FRAME; 520 } 521 printf("\n"); 522 523#ifdef QUERY_METADATA 524 /* ------------------------------------------------------ */ 525 /* Display the metadata obtained from the decoder */ 526 // This is for test / demonstration purposes only where we discover the key and value sizes 527 // of a PCM decoder. An application that would want to directly get access to those values 528 // can make assumptions about the size of the keys and their matching values (all SLuint32) 529 SLuint32 itemCount; 530 res = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount); 531 ExitOnError(res); 532 printf("itemCount=%u\n", itemCount); 533 SLuint32 keySize, valueSize; 534 SLMetadataInfo *keyInfo, *value; 535 for(i=0 ; i<itemCount ; i++) { 536 keyInfo = NULL; keySize = 0; 537 value = NULL; valueSize = 0; 538 res = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize); 539 ExitOnError(res); 540 res = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize); 541 ExitOnError(res); 542 keyInfo = (SLMetadataInfo*) malloc(keySize); 543 if (NULL != keyInfo) { 544 res = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo); 545 ExitOnError(res); 546 printf("key[%d] size=%d, name=%s \tvalue size=%d encoding=0x%X langCountry=%s\n", 547 i, keyInfo->size, keyInfo->data, valueSize, keyInfo->encoding, 548 keyInfo->langCountry); 549 /* find out the key index of the metadata we're interested in */ 550 if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS)) { 551 channelCountKeyIndex = i; 552 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE)) { 553 sampleRateKeyIndex = i; 554 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE)) { 555 bitsPerSampleKeyIndex = i; 556 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE)) { 557 containerSizeKeyIndex = i; 558 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_CHANNELMASK)) { 559 channelMaskKeyIndex = i; 560 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_ENDIANNESS)) { 561 endiannessKeyIndex = i; 562 } else { 563 printf("Unknown key %s ignored\n", (char *)keyInfo->data); 564 } 565 free(keyInfo); 566 } 567 } 568 if (channelCountKeyIndex != -1) { 569 printf("Key %s is at index %d\n", 570 ANDROID_KEY_PCMFORMAT_NUMCHANNELS, channelCountKeyIndex); 571 } else { 572 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_NUMCHANNELS); 573 } 574 if (sampleRateKeyIndex != -1) { 575 printf("Key %s is at index %d\n", 576 ANDROID_KEY_PCMFORMAT_SAMPLERATE, sampleRateKeyIndex); 577 } else { 578 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_SAMPLERATE); 579 } 580 if (bitsPerSampleKeyIndex != -1) { 581 printf("Key %s is at index %d\n", 582 ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE, bitsPerSampleKeyIndex); 583 } else { 584 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE); 585 } 586 if (containerSizeKeyIndex != -1) { 587 printf("Key %s is at index %d\n", 588 ANDROID_KEY_PCMFORMAT_CONTAINERSIZE, containerSizeKeyIndex); 589 } else { 590 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_CONTAINERSIZE); 591 } 592 if (channelMaskKeyIndex != -1) { 593 printf("Key %s is at index %d\n", 594 ANDROID_KEY_PCMFORMAT_CHANNELMASK, channelMaskKeyIndex); 595 } else { 596 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_CHANNELMASK); 597 } 598 if (endiannessKeyIndex != -1) { 599 printf("Key %s is at index %d\n", 600 ANDROID_KEY_PCMFORMAT_ENDIANNESS, endiannessKeyIndex); 601 } else { 602 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_ENDIANNESS); 603 } 604#endif 605 606 /* ------------------------------------------------------ */ 607 /* Start decoding */ 608 printf("Starting to decode\n"); 609 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 610 ExitOnError(res); 611 612 /* Decode until the end of the stream is reached */ 613 pthread_mutex_lock(&eosLock); 614 while (!eos) { 615 pthread_cond_wait(&eosCondition, &eosLock); 616 } 617 pthread_mutex_unlock(&eosLock); 618 619 /* This just means done enqueueing; there may still more data in decode queue! */ 620 usleep(100 * 1000); 621 622 pthread_mutex_lock(&eosLock); 623 printf("Frame counters: encoded=%u decoded=%u\n", encodedFrames, decodedFrames); 624 printf("Sample counters: encoded=%u decoded=%u\n", encodedSamples, decodedSamples); 625 pthread_mutex_unlock(&eosLock); 626 627 /* Get the final position and duration */ 628 res = (*playItf)->GetPosition(playItf, &position); 629 ExitOnError(res); 630 res = (*playItf)->GetDuration(playItf, &duration); 631 ExitOnError(res); 632 if (duration == SL_TIME_UNKNOWN) { 633 printf("The final position is %u ms, duration is unknown\n", position); 634 } else { 635 printf("The final position is %u ms, duration is %u ms\n", position, duration); 636 } 637 638 /* ------------------------------------------------------ */ 639 /* End of decoding */ 640 641destroyRes: 642 /* Destroy the AudioPlayer object */ 643 (*player)->Destroy(player); 644 645 fclose(outputFp); 646 647 // unmap the ADTS AAC file from memory 648 ok = munmap(ptr, statbuf.st_size); 649 if (0 != ok) { 650 perror(path); 651 } 652} 653 654//----------------------------------------------------------------- 655int main(int argc, char* const argv[]) 656{ 657 SLresult res; 658 SLObjectItf sl; 659 660 printf("OpenSL ES test %s: decodes a file containing AAC ADTS data\n", argv[0]); 661 662 if (argc != 2) { 663 printf("Usage: \t%s source_file\n", argv[0]); 664 printf("Example: \"%s /sdcard/myFile.adts\n", argv[0]); 665 exit(EXIT_FAILURE); 666 } 667 668 // open pathname of encoded ADTS AAC file to get a file descriptor 669 int fd; 670 fd = open(argv[1], O_RDONLY); 671 if (fd < 0) { 672 perror(argv[1]); 673 return EXIT_FAILURE; 674 } 675 676 SLEngineOption EngineOption[] = { 677 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 678 }; 679 680 res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 681 ExitOnError(res); 682 683 /* Realizing the SL Engine in synchronous mode. */ 684 res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 685 ExitOnError(res); 686 687 TestDecToBuffQueue(sl, argv[1], fd); 688 689 /* Shutdown OpenSL ES */ 690 (*sl)->Destroy(sl); 691 692 // close the file 693 (void) close(fd); 694 695 return EXIT_SUCCESS; 696} 697