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