1 /* 2 ** 3 ** Copyright 2010, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 19 //#define LOG_NDEBUG 0 20 #define LOG_TAG "MediaProfiles" 21 22 #include <stdlib.h> 23 #include <utils/Log.h> 24 #include <utils/Vector.h> 25 #include <cutils/properties.h> 26 #include <expat.h> 27 #include <media/MediaProfiles.h> 28 #include <media/stagefright/foundation/ADebug.h> 29 #include <OMX_Video.h> 30 #include <sys/stat.h> 31 32 namespace android { 33 34 constexpr char const * const MediaProfiles::xmlFiles[]; 35 Mutex MediaProfiles::sLock; 36 bool MediaProfiles::sIsInitialized = false; 37 MediaProfiles *MediaProfiles::sInstance = NULL; 38 39 const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = { 40 {"h263", VIDEO_ENCODER_H263}, 41 {"h264", VIDEO_ENCODER_H264}, 42 {"m4v", VIDEO_ENCODER_MPEG_4_SP}, 43 {"hevc", VIDEO_ENCODER_HEVC} 44 }; 45 46 const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = { 47 {"amrnb", AUDIO_ENCODER_AMR_NB}, 48 {"amrwb", AUDIO_ENCODER_AMR_WB}, 49 {"aac", AUDIO_ENCODER_AAC}, 50 {"heaac", AUDIO_ENCODER_HE_AAC}, 51 {"aaceld", AUDIO_ENCODER_AAC_ELD} 52 }; 53 54 const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = { 55 {"3gp", OUTPUT_FORMAT_THREE_GPP}, 56 {"mp4", OUTPUT_FORMAT_MPEG_4} 57 }; 58 59 const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = { 60 {"wmv", VIDEO_DECODER_WMV} 61 }; 62 63 const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = { 64 {"wma", AUDIO_DECODER_WMA} 65 }; 66 67 const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { 68 {"low", CAMCORDER_QUALITY_LOW}, 69 {"high", CAMCORDER_QUALITY_HIGH}, 70 {"qcif", CAMCORDER_QUALITY_QCIF}, 71 {"cif", CAMCORDER_QUALITY_CIF}, 72 {"480p", CAMCORDER_QUALITY_480P}, 73 {"720p", CAMCORDER_QUALITY_720P}, 74 {"1080p", CAMCORDER_QUALITY_1080P}, 75 {"2160p", CAMCORDER_QUALITY_2160P}, 76 {"qvga", CAMCORDER_QUALITY_QVGA}, 77 78 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW}, 79 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH}, 80 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF}, 81 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF}, 82 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P}, 83 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P}, 84 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P}, 85 {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P}, 86 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA}, 87 88 {"highspeedlow", CAMCORDER_QUALITY_HIGH_SPEED_LOW}, 89 {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH}, 90 {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P}, 91 {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P}, 92 {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P}, 93 {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P}, 94 }; 95 96 #if LOG_NDEBUG 97 #define UNUSED __unused 98 #else 99 #define UNUSED 100 #endif 101 102 /*static*/ void 103 MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED) 104 { 105 ALOGV("video codec:"); 106 ALOGV("codec = %d", codec.mCodec); 107 ALOGV("bit rate: %d", codec.mBitRate); 108 ALOGV("frame width: %d", codec.mFrameWidth); 109 ALOGV("frame height: %d", codec.mFrameHeight); 110 ALOGV("frame rate: %d", codec.mFrameRate); 111 } 112 113 /*static*/ void 114 MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED) 115 { 116 ALOGV("audio codec:"); 117 ALOGV("codec = %d", codec.mCodec); 118 ALOGV("bit rate: %d", codec.mBitRate); 119 ALOGV("sample rate: %d", codec.mSampleRate); 120 ALOGV("number of channels: %d", codec.mChannels); 121 } 122 123 /*static*/ void 124 MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED) 125 { 126 ALOGV("video encoder cap:"); 127 ALOGV("codec = %d", cap.mCodec); 128 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate); 129 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth); 130 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight); 131 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate); 132 } 133 134 /*static*/ void 135 MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED) 136 { 137 ALOGV("audio encoder cap:"); 138 ALOGV("codec = %d", cap.mCodec); 139 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate); 140 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate); 141 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels); 142 } 143 144 /*static*/ void 145 MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED) 146 { 147 ALOGV("video decoder cap:"); 148 ALOGV("codec = %d", cap.mCodec); 149 } 150 151 /*static*/ void 152 MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED) 153 { 154 ALOGV("audio codec cap:"); 155 ALOGV("codec = %d", cap.mCodec); 156 } 157 158 /*static*/ int 159 MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, 160 const char *name) 161 { 162 int tag = -1; 163 for (size_t i = 0; i < nMappings; ++i) { 164 if (!strcmp(map[i].name, name)) { 165 tag = map[i].tag; 166 break; 167 } 168 } 169 return tag; 170 } 171 172 /*static*/ MediaProfiles::VideoCodec* 173 MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles) 174 { 175 CHECK(!strcmp("codec", atts[0]) && 176 !strcmp("bitRate", atts[2]) && 177 !strcmp("width", atts[4]) && 178 !strcmp("height", atts[6]) && 179 !strcmp("frameRate", atts[8])); 180 181 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]); 182 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]); 183 CHECK(codec != -1); 184 185 MediaProfiles::VideoCodec *videoCodec = 186 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec), 187 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9])); 188 logVideoCodec(*videoCodec); 189 190 size_t nCamcorderProfiles; 191 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1); 192 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec; 193 return videoCodec; 194 } 195 196 /*static*/ MediaProfiles::AudioCodec* 197 MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles) 198 { 199 CHECK(!strcmp("codec", atts[0]) && 200 !strcmp("bitRate", atts[2]) && 201 !strcmp("sampleRate", atts[4]) && 202 !strcmp("channels", atts[6])); 203 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]); 204 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]); 205 CHECK(codec != -1); 206 207 MediaProfiles::AudioCodec *audioCodec = 208 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec), 209 atoi(atts[3]), atoi(atts[5]), atoi(atts[7])); 210 logAudioCodec(*audioCodec); 211 212 size_t nCamcorderProfiles; 213 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1); 214 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec; 215 return audioCodec; 216 } 217 /*static*/ MediaProfiles::AudioDecoderCap* 218 MediaProfiles::createAudioDecoderCap(const char **atts) 219 { 220 CHECK(!strcmp("name", atts[0]) && 221 !strcmp("enabled", atts[2])); 222 223 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]); 224 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]); 225 CHECK(codec != -1); 226 227 MediaProfiles::AudioDecoderCap *cap = 228 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec)); 229 logAudioDecoderCap(*cap); 230 return cap; 231 } 232 233 /*static*/ MediaProfiles::VideoDecoderCap* 234 MediaProfiles::createVideoDecoderCap(const char **atts) 235 { 236 CHECK(!strcmp("name", atts[0]) && 237 !strcmp("enabled", atts[2])); 238 239 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]); 240 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]); 241 CHECK(codec != -1); 242 243 MediaProfiles::VideoDecoderCap *cap = 244 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec)); 245 logVideoDecoderCap(*cap); 246 return cap; 247 } 248 249 /*static*/ MediaProfiles::VideoEncoderCap* 250 MediaProfiles::createVideoEncoderCap(const char **atts) 251 { 252 CHECK(!strcmp("name", atts[0]) && 253 !strcmp("enabled", atts[2]) && 254 !strcmp("minBitRate", atts[4]) && 255 !strcmp("maxBitRate", atts[6]) && 256 !strcmp("minFrameWidth", atts[8]) && 257 !strcmp("maxFrameWidth", atts[10]) && 258 !strcmp("minFrameHeight", atts[12]) && 259 !strcmp("maxFrameHeight", atts[14]) && 260 !strcmp("minFrameRate", atts[16]) && 261 !strcmp("maxFrameRate", atts[18])); 262 263 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]); 264 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]); 265 CHECK(codec != -1); 266 267 MediaProfiles::VideoEncoderCap *cap = 268 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec), 269 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), 270 atoi(atts[15]), atoi(atts[17]), atoi(atts[19])); 271 logVideoEncoderCap(*cap); 272 return cap; 273 } 274 275 /*static*/ MediaProfiles::AudioEncoderCap* 276 MediaProfiles::createAudioEncoderCap(const char **atts) 277 { 278 CHECK(!strcmp("name", atts[0]) && 279 !strcmp("enabled", atts[2]) && 280 !strcmp("minBitRate", atts[4]) && 281 !strcmp("maxBitRate", atts[6]) && 282 !strcmp("minSampleRate", atts[8]) && 283 !strcmp("maxSampleRate", atts[10]) && 284 !strcmp("minChannels", atts[12]) && 285 !strcmp("maxChannels", atts[14])); 286 287 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]); 288 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]); 289 CHECK(codec != -1); 290 291 MediaProfiles::AudioEncoderCap *cap = 292 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), 293 atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15])); 294 logAudioEncoderCap(*cap); 295 return cap; 296 } 297 298 /*static*/ output_format 299 MediaProfiles::createEncoderOutputFileFormat(const char **atts) 300 { 301 CHECK(!strcmp("name", atts[0])); 302 303 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]); 304 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]); 305 CHECK(format != -1); 306 307 return static_cast<output_format>(format); 308 } 309 310 static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) { 311 for (int i = 0, n = cameraIds.size(); i < n; ++i) { 312 if (cameraId == cameraIds[i]) { 313 return true; 314 } 315 } 316 return false; 317 } 318 319 /*static*/ MediaProfiles::CamcorderProfile* 320 MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds) 321 { 322 CHECK(!strcmp("quality", atts[0]) && 323 !strcmp("fileFormat", atts[2]) && 324 !strcmp("duration", atts[4])); 325 326 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/ 327 sizeof(sCamcorderQualityNameMap[0]); 328 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]); 329 CHECK(quality != -1); 330 331 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]); 332 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]); 333 CHECK(fileFormat != -1); 334 335 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; 336 profile->mCameraId = cameraId; 337 if (!isCameraIdFound(cameraId, cameraIds)) { 338 cameraIds.add(cameraId); 339 } 340 profile->mFileFormat = static_cast<output_format>(fileFormat); 341 profile->mQuality = static_cast<camcorder_quality>(quality); 342 profile->mDuration = atoi(atts[5]); 343 return profile; 344 } 345 346 MediaProfiles::ImageEncodingQualityLevels* 347 MediaProfiles::findImageEncodingQualityLevels(int cameraId) const 348 { 349 int n = mImageEncodingQualityLevels.size(); 350 for (int i = 0; i < n; i++) { 351 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i]; 352 if (levels->mCameraId == cameraId) { 353 return levels; 354 } 355 } 356 return NULL; 357 } 358 359 void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts) 360 { 361 CHECK(!strcmp("quality", atts[0])); 362 int quality = atoi(atts[1]); 363 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality); 364 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId); 365 366 if (levels == NULL) { 367 levels = new ImageEncodingQualityLevels(); 368 levels->mCameraId = cameraId; 369 mImageEncodingQualityLevels.add(levels); 370 } 371 372 levels->mLevels.add(quality); 373 } 374 375 /*static*/ int 376 MediaProfiles::getCameraId(const char** atts) 377 { 378 if (!atts[0]) return 0; // default cameraId = 0 379 CHECK(!strcmp("cameraId", atts[0])); 380 return atoi(atts[1]); 381 } 382 383 void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts) 384 { 385 int offsetTimeMs = 1000; 386 if (atts[2]) { 387 CHECK(!strcmp("startOffsetMs", atts[2])); 388 offsetTimeMs = atoi(atts[3]); 389 } 390 391 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs); 392 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs); 393 } 394 395 /*static*/ void 396 MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts) 397 { 398 MediaProfiles *profiles = (MediaProfiles *) userData; 399 if (strcmp("Video", name) == 0) { 400 createVideoCodec(atts, profiles); 401 } else if (strcmp("Audio", name) == 0) { 402 createAudioCodec(atts, profiles); 403 } else if (strcmp("VideoEncoderCap", name) == 0 && 404 strcmp("true", atts[3]) == 0) { 405 profiles->mVideoEncoders.add(createVideoEncoderCap(atts)); 406 } else if (strcmp("AudioEncoderCap", name) == 0 && 407 strcmp("true", atts[3]) == 0) { 408 profiles->mAudioEncoders.add(createAudioEncoderCap(atts)); 409 } else if (strcmp("VideoDecoderCap", name) == 0 && 410 strcmp("true", atts[3]) == 0) { 411 profiles->mVideoDecoders.add(createVideoDecoderCap(atts)); 412 } else if (strcmp("AudioDecoderCap", name) == 0 && 413 strcmp("true", atts[3]) == 0) { 414 profiles->mAudioDecoders.add(createAudioDecoderCap(atts)); 415 } else if (strcmp("EncoderOutputFileFormat", name) == 0) { 416 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts)); 417 } else if (strcmp("CamcorderProfiles", name) == 0) { 418 profiles->mCurrentCameraId = getCameraId(atts); 419 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts); 420 } else if (strcmp("EncoderProfile", name) == 0) { 421 profiles->mCamcorderProfiles.add( 422 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds)); 423 } else if (strcmp("ImageEncoding", name) == 0) { 424 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts); 425 } 426 } 427 428 static bool isCamcorderProfile(camcorder_quality quality) { 429 return quality >= CAMCORDER_QUALITY_LIST_START && 430 quality <= CAMCORDER_QUALITY_LIST_END; 431 } 432 433 static bool isTimelapseProfile(camcorder_quality quality) { 434 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START && 435 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END; 436 } 437 438 static bool isHighSpeedProfile(camcorder_quality quality) { 439 return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START && 440 quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END; 441 } 442 443 void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) { 444 ALOGV("Number of camera ids: %zu", cameraIds.size()); 445 CHECK(cameraIds.size() > 0); 446 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()]; 447 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) { 448 mRequiredProfileRefs[i].mCameraId = cameraIds[i]; 449 for (size_t j = 0; j < kNumRequiredProfiles; ++j) { 450 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false; 451 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1; 452 if ((j & 1) == 0) { // low resolution 453 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF; 454 } else { // high resolution 455 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0; 456 } 457 } 458 } 459 } 460 461 int MediaProfiles::getRequiredProfileRefIndex(int cameraId) { 462 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) { 463 if (mCameraIds[i] == cameraId) { 464 return i; 465 } 466 } 467 return -1; 468 } 469 470 void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() { 471 if (sIsInitialized) { 472 return; 473 } 474 475 initRequiredProfileRefs(mCameraIds); 476 477 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) { 478 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth * 479 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight; 480 481 camcorder_quality quality = mCamcorderProfiles[i]->mQuality; 482 int cameraId = mCamcorderProfiles[i]->mCameraId; 483 int index = -1; 484 int refIndex = getRequiredProfileRefIndex(cameraId); 485 CHECK(refIndex != -1); 486 RequiredProfileRefInfo *info; 487 camcorder_quality refQuality; 488 489 // Check high and low from either camcorder profile, timelapse profile 490 // or high speed profile, but not all of them. Default, check camcorder profile 491 size_t j = 0; 492 size_t o = 2; 493 if (isTimelapseProfile(quality)) { 494 // Check timelapse profile instead. 495 j = 2; 496 o = kNumRequiredProfiles; 497 } else if (isHighSpeedProfile(quality)) { 498 // Skip the check for high speed profile. 499 continue; 500 } else { 501 // Must be camcorder profile. 502 CHECK(isCamcorderProfile(quality)); 503 } 504 for (; j < o; ++j) { 505 info = &(mRequiredProfileRefs[refIndex].mRefs[j]); 506 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low 507 (j % 2 != 0 && product < info->mResolutionProduct)) { // high 508 continue; 509 } 510 switch (j) { 511 case 0: 512 refQuality = CAMCORDER_QUALITY_LOW; 513 break; 514 case 1: 515 refQuality = CAMCORDER_QUALITY_HIGH; 516 break; 517 case 2: 518 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW; 519 break; 520 case 3: 521 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH; 522 break; 523 default: 524 CHECK(!"Should never reach here"); 525 } 526 527 if (!info->mHasRefProfile) { 528 index = getCamcorderProfileIndex(cameraId, refQuality); 529 } 530 if (index == -1) { 531 // New high or low quality profile is found. 532 // Update its reference. 533 info->mHasRefProfile = true; 534 info->mRefProfileIndex = i; 535 info->mResolutionProduct = product; 536 } 537 } 538 } 539 540 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) { 541 for (size_t j = 0; j < kNumRequiredProfiles; ++j) { 542 int refIndex = getRequiredProfileRefIndex(cameraId); 543 CHECK(refIndex != -1); 544 RequiredProfileRefInfo *info = 545 &mRequiredProfileRefs[refIndex].mRefs[j]; 546 547 if (info->mHasRefProfile) { 548 549 CamcorderProfile *profile = 550 new CamcorderProfile( 551 *mCamcorderProfiles[info->mRefProfileIndex]); 552 553 // Overwrite the quality 554 switch (j % kNumRequiredProfiles) { 555 case 0: 556 profile->mQuality = CAMCORDER_QUALITY_LOW; 557 break; 558 case 1: 559 profile->mQuality = CAMCORDER_QUALITY_HIGH; 560 break; 561 case 2: 562 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW; 563 break; 564 case 3: 565 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH; 566 break; 567 default: 568 CHECK(!"Should never come here"); 569 } 570 571 int index = getCamcorderProfileIndex(cameraId, profile->mQuality); 572 if (index != -1) { 573 ALOGV("Profile quality %d for camera %zu already exists", 574 profile->mQuality, cameraId); 575 CHECK(index == refIndex); 576 continue; 577 } 578 579 // Insert the new profile 580 ALOGV("Add a profile: quality %d=>%d for camera %zu", 581 mCamcorderProfiles[info->mRefProfileIndex]->mQuality, 582 profile->mQuality, cameraId); 583 584 mCamcorderProfiles.add(profile); 585 } 586 } 587 } 588 } 589 590 /*static*/ MediaProfiles* 591 MediaProfiles::getInstance() 592 { 593 ALOGV("getInstance"); 594 Mutex::Autolock lock(sLock); 595 if (!sIsInitialized) { 596 char value[PROPERTY_VALUE_MAX]; 597 if (property_get("media.settings.xml", value, NULL) <= 0) { 598 const char* xmlFile = nullptr; 599 for (auto const& f : xmlFiles) { 600 if (checkXmlFile(f)) { 601 xmlFile = f; 602 break; 603 } 604 } 605 if (xmlFile == nullptr) { 606 ALOGW("Could not find a validated xml file. " 607 "Using the default instance instead."); 608 sInstance = createDefaultInstance(); 609 } else { 610 sInstance = createInstanceFromXmlFile(xmlFile); 611 } 612 } else { 613 sInstance = createInstanceFromXmlFile(value); 614 } 615 CHECK(sInstance != NULL); 616 sInstance->checkAndAddRequiredProfilesIfNecessary(); 617 sIsInitialized = true; 618 } 619 620 return sInstance; 621 } 622 623 /*static*/ MediaProfiles::VideoEncoderCap* 624 MediaProfiles::createDefaultH263VideoEncoderCap() 625 { 626 return new MediaProfiles::VideoEncoderCap( 627 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20); 628 } 629 630 /*static*/ MediaProfiles::VideoEncoderCap* 631 MediaProfiles::createDefaultM4vVideoEncoderCap() 632 { 633 return new MediaProfiles::VideoEncoderCap( 634 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20); 635 } 636 637 638 /*static*/ void 639 MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles) 640 { 641 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap()); 642 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap()); 643 } 644 645 /*static*/ MediaProfiles::CamcorderProfile* 646 MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality) 647 { 648 MediaProfiles::VideoCodec *videoCodec = 649 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20); 650 651 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1); 652 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; 653 profile->mCameraId = 0; 654 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP; 655 profile->mQuality = quality; 656 profile->mDuration = 60; 657 profile->mVideoCodec = videoCodec; 658 profile->mAudioCodec = audioCodec; 659 return profile; 660 } 661 662 /*static*/ MediaProfiles::CamcorderProfile* 663 MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality) 664 { 665 MediaProfiles::VideoCodec *videoCodec = 666 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20); 667 668 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1); 669 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; 670 profile->mCameraId = 0; 671 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP; 672 profile->mQuality = quality; 673 profile->mDuration = 60; 674 profile->mVideoCodec = videoCodec; 675 profile->mAudioCodec = audioCodec; 676 return profile; 677 } 678 679 /*static*/ void 680 MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles( 681 MediaProfiles::CamcorderProfile **lowTimeLapseProfile, 682 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) { 683 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile( 684 CAMCORDER_QUALITY_TIME_LAPSE_LOW); 685 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile( 686 CAMCORDER_QUALITY_TIME_LAPSE_QCIF); 687 } 688 689 /*static*/ void 690 MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles( 691 MediaProfiles::CamcorderProfile **highTimeLapseProfile, 692 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) { 693 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile( 694 CAMCORDER_QUALITY_TIME_LAPSE_HIGH); 695 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile( 696 CAMCORDER_QUALITY_TIME_LAPSE_480P); 697 } 698 699 /*static*/ MediaProfiles::CamcorderProfile* 700 MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality) 701 { 702 MediaProfiles::VideoCodec *videoCodec = 703 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20); 704 705 MediaProfiles::AudioCodec *audioCodec = 706 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1); 707 708 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; 709 profile->mCameraId = 0; 710 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP; 711 profile->mQuality = quality; 712 profile->mDuration = 30; 713 profile->mVideoCodec = videoCodec; 714 profile->mAudioCodec = audioCodec; 715 return profile; 716 } 717 718 /*static*/ MediaProfiles::CamcorderProfile* 719 MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality) 720 { 721 MediaProfiles::VideoCodec *videoCodec = 722 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20); 723 724 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1); 725 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; 726 profile->mCameraId = 0; 727 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP; 728 profile->mQuality = quality; 729 profile->mDuration = 60; 730 profile->mVideoCodec = videoCodec; 731 profile->mAudioCodec = audioCodec; 732 return profile; 733 } 734 735 /*static*/ void 736 MediaProfiles::createDefaultCamcorderLowProfiles( 737 MediaProfiles::CamcorderProfile **lowProfile, 738 MediaProfiles::CamcorderProfile **lowSpecificProfile) { 739 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW); 740 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF); 741 } 742 743 /*static*/ void 744 MediaProfiles::createDefaultCamcorderHighProfiles( 745 MediaProfiles::CamcorderProfile **highProfile, 746 MediaProfiles::CamcorderProfile **highSpecificProfile) { 747 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH); 748 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF); 749 } 750 751 /*static*/ void 752 MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles) 753 { 754 // low camcorder profiles. 755 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile; 756 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile); 757 profiles->mCamcorderProfiles.add(lowProfile); 758 profiles->mCamcorderProfiles.add(lowSpecificProfile); 759 760 // high camcorder profiles. 761 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile; 762 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile); 763 profiles->mCamcorderProfiles.add(highProfile); 764 profiles->mCamcorderProfiles.add(highSpecificProfile); 765 766 // low camcorder time lapse profiles. 767 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile; 768 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile); 769 profiles->mCamcorderProfiles.add(lowTimeLapseProfile); 770 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile); 771 772 // high camcorder time lapse profiles. 773 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile; 774 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, 775 &highSpecificTimeLapseProfile); 776 profiles->mCamcorderProfiles.add(highTimeLapseProfile); 777 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile); 778 779 // For emulator and other legacy devices which does not have a 780 // media_profiles.xml file, We assume that the default camera id 781 // is 0 and that is the only camera available. 782 profiles->mCameraIds.push(0); 783 } 784 785 /*static*/ void 786 MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles) 787 { 788 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap()); 789 } 790 791 /*static*/ void 792 MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles) 793 { 794 MediaProfiles::VideoDecoderCap *cap = 795 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV); 796 797 profiles->mVideoDecoders.add(cap); 798 } 799 800 /*static*/ void 801 MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles) 802 { 803 MediaProfiles::AudioDecoderCap *cap = 804 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA); 805 806 profiles->mAudioDecoders.add(cap); 807 } 808 809 /*static*/ void 810 MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles) 811 { 812 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP); 813 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4); 814 } 815 816 /*static*/ MediaProfiles::AudioEncoderCap* 817 MediaProfiles::createDefaultAmrNBEncoderCap() 818 { 819 return new MediaProfiles::AudioEncoderCap( 820 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1); 821 } 822 823 /*static*/ void 824 MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles) 825 { 826 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels(); 827 levels->mCameraId = 0; 828 levels->mLevels.add(70); 829 levels->mLevels.add(80); 830 levels->mLevels.add(90); 831 profiles->mImageEncodingQualityLevels.add(levels); 832 } 833 834 /*static*/ MediaProfiles* 835 MediaProfiles::createDefaultInstance() 836 { 837 MediaProfiles *profiles = new MediaProfiles; 838 createDefaultCamcorderProfiles(profiles); 839 createDefaultVideoEncoders(profiles); 840 createDefaultAudioEncoders(profiles); 841 createDefaultVideoDecoders(profiles); 842 createDefaultAudioDecoders(profiles); 843 createDefaultEncoderOutputFileFormats(profiles); 844 createDefaultImageEncodingQualityLevels(profiles); 845 return profiles; 846 } 847 848 bool MediaProfiles::checkXmlFile(const char* xmlFile) { 849 struct stat fStat; 850 return stat(xmlFile, &fStat) == 0 && S_ISREG(fStat.st_mode); 851 // TODO: Add validation 852 } 853 854 /*static*/ MediaProfiles* 855 MediaProfiles::createInstanceFromXmlFile(const char *xml) 856 { 857 FILE *fp = NULL; 858 CHECK((fp = fopen(xml, "r"))); 859 860 XML_Parser parser = ::XML_ParserCreate(NULL); 861 CHECK(parser != NULL); 862 863 MediaProfiles *profiles = new MediaProfiles(); 864 ::XML_SetUserData(parser, profiles); 865 ::XML_SetElementHandler(parser, startElementHandler, NULL); 866 867 /* 868 FIXME: 869 expat is not compiled with -DXML_DTD. We don't have DTD parsing support. 870 871 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) { 872 ALOGE("failed to enable DTD support in the xml file"); 873 return UNKNOWN_ERROR; 874 } 875 876 */ 877 878 const int BUFF_SIZE = 512; 879 for (;;) { 880 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE); 881 if (buff == NULL) { 882 ALOGE("failed to in call to XML_GetBuffer()"); 883 delete profiles; 884 profiles = NULL; 885 goto exit; 886 } 887 888 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp); 889 if (bytes_read < 0) { 890 ALOGE("failed in call to read"); 891 delete profiles; 892 profiles = NULL; 893 goto exit; 894 } 895 896 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0)); 897 898 if (bytes_read == 0) break; // done parsing the xml file 899 } 900 901 exit: 902 ::XML_ParserFree(parser); 903 ::fclose(fp); 904 return profiles; 905 } 906 907 Vector<output_format> MediaProfiles::getOutputFileFormats() const 908 { 909 return mEncoderOutputFileFormats; // copy out 910 } 911 912 Vector<video_encoder> MediaProfiles::getVideoEncoders() const 913 { 914 Vector<video_encoder> encoders; 915 for (size_t i = 0; i < mVideoEncoders.size(); ++i) { 916 encoders.add(mVideoEncoders[i]->mCodec); 917 } 918 return encoders; // copy out 919 } 920 921 int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const 922 { 923 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec); 924 int index = -1; 925 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) { 926 if (mVideoEncoders[i]->mCodec == codec) { 927 index = i; 928 break; 929 } 930 } 931 if (index == -1) { 932 ALOGE("The given video encoder %d is not found", codec); 933 return -1; 934 } 935 936 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth; 937 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth; 938 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight; 939 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight; 940 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate; 941 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate; 942 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate; 943 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate; 944 945 ALOGE("The given video encoder param name %s is not found", name); 946 return -1; 947 } 948 949 Vector<audio_encoder> MediaProfiles::getAudioEncoders() const 950 { 951 Vector<audio_encoder> encoders; 952 for (size_t i = 0; i < mAudioEncoders.size(); ++i) { 953 encoders.add(mAudioEncoders[i]->mCodec); 954 } 955 return encoders; // copy out 956 } 957 958 int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const 959 { 960 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec); 961 int index = -1; 962 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) { 963 if (mAudioEncoders[i]->mCodec == codec) { 964 index = i; 965 break; 966 } 967 } 968 if (index == -1) { 969 ALOGE("The given audio encoder %d is not found", codec); 970 return -1; 971 } 972 973 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels; 974 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels; 975 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate; 976 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate; 977 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate; 978 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate; 979 980 ALOGE("The given audio encoder param name %s is not found", name); 981 return -1; 982 } 983 984 Vector<video_decoder> MediaProfiles::getVideoDecoders() const 985 { 986 Vector<video_decoder> decoders; 987 for (size_t i = 0; i < mVideoDecoders.size(); ++i) { 988 decoders.add(mVideoDecoders[i]->mCodec); 989 } 990 return decoders; // copy out 991 } 992 993 Vector<audio_decoder> MediaProfiles::getAudioDecoders() const 994 { 995 Vector<audio_decoder> decoders; 996 for (size_t i = 0; i < mAudioDecoders.size(); ++i) { 997 decoders.add(mAudioDecoders[i]->mCodec); 998 } 999 return decoders; // copy out 1000 } 1001 1002 int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const 1003 { 1004 int index = -1; 1005 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) { 1006 if (mCamcorderProfiles[i]->mCameraId == cameraId && 1007 mCamcorderProfiles[i]->mQuality == quality) { 1008 index = i; 1009 break; 1010 } 1011 } 1012 return index; 1013 } 1014 1015 int MediaProfiles::getCamcorderProfileParamByName(const char *name, 1016 int cameraId, 1017 camcorder_quality quality) const 1018 { 1019 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d", 1020 name, cameraId, quality); 1021 1022 int index = getCamcorderProfileIndex(cameraId, quality); 1023 if (index == -1) { 1024 ALOGE("The given camcorder profile camera %d quality %d is not found", 1025 cameraId, quality); 1026 return -1; 1027 } 1028 1029 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration; 1030 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat; 1031 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec; 1032 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth; 1033 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight; 1034 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate; 1035 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate; 1036 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec; 1037 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate; 1038 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels; 1039 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate; 1040 1041 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name); 1042 return -1; 1043 } 1044 1045 bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const 1046 { 1047 return (getCamcorderProfileIndex(cameraId, quality) != -1); 1048 } 1049 1050 Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const 1051 { 1052 Vector<int> result; 1053 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId); 1054 if (levels != NULL) { 1055 result = levels->mLevels; // copy out 1056 } 1057 return result; 1058 } 1059 1060 int MediaProfiles::getStartTimeOffsetMs(int cameraId) const { 1061 int offsetTimeMs = -1; 1062 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId); 1063 if (index >= 0) { 1064 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId); 1065 } 1066 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId); 1067 return offsetTimeMs; 1068 } 1069 1070 MediaProfiles::~MediaProfiles() 1071 { 1072 CHECK("destructor should never be called" == 0); 1073 #if 0 1074 for (size_t i = 0; i < mAudioEncoders.size(); ++i) { 1075 delete mAudioEncoders[i]; 1076 } 1077 mAudioEncoders.clear(); 1078 1079 for (size_t i = 0; i < mVideoEncoders.size(); ++i) { 1080 delete mVideoEncoders[i]; 1081 } 1082 mVideoEncoders.clear(); 1083 1084 for (size_t i = 0; i < mVideoDecoders.size(); ++i) { 1085 delete mVideoDecoders[i]; 1086 } 1087 mVideoDecoders.clear(); 1088 1089 for (size_t i = 0; i < mAudioDecoders.size(); ++i) { 1090 delete mAudioDecoders[i]; 1091 } 1092 mAudioDecoders.clear(); 1093 1094 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) { 1095 delete mCamcorderProfiles[i]; 1096 } 1097 mCamcorderProfiles.clear(); 1098 #endif 1099 } 1100 } // namespace android 1101