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