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