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